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
)
1259 struct handle_info
*hi
;
1260 const char *email_addr
, *password
;
1261 char syncpass
[MD5_CRYPT_LENGTH
];
1262 int no_auth
, weblink
;
1264 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1265 /* Require the first handle registered to belong to someone +o. */
1266 reply("NSMSG_REQUIRE_OPER");
1270 if (user
->handle_info
) {
1271 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1275 if (IsRegistering(user
)) {
1276 reply("NSMSG_ALREADY_REGISTERING");
1280 if (IsStamped(user
)) {
1281 /* Unauthenticated users might still have been stamped
1282 previously and could therefore have a hidden host;
1283 do not allow them to register a new account. */
1284 reply("NSMSG_STAMPED_REGISTER");
1288 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1290 if (!is_valid_handle(argv
[1])) {
1291 reply("NSMSG_BAD_HANDLE", argv
[1]);
1296 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1297 struct handle_info_list
*hil
;
1300 /* Remember email address. */
1301 email_addr
= argv
[3];
1303 /* Check that the email address looks valid.. */
1304 if (!valid_email(email_addr
)) {
1305 reply("NSMSG_BAD_EMAIL_ADDR");
1309 /* .. and that we are allowed to send to it. */
1310 if ((str
= sendmail_prohibited_address(email_addr
))) {
1311 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1315 /* If we do email verify, make sure we don't spam the address. */
1316 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1318 for (nn
=0; nn
<hil
->used
; nn
++) {
1319 if (hil
->list
[nn
]->cookie
) {
1320 reply("NSMSG_EMAIL_UNACTIVATED");
1324 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1325 reply("NSMSG_EMAIL_OVERUSED");
1338 /* Webregister hack - send URL instead of IRC cookie
1341 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1345 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1347 /* Add any masks they should get. */
1348 if (nickserv_conf
.default_hostmask
) {
1349 string_list_append(hi
->masks
, strdup("*@*"));
1351 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1352 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1353 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1356 /* If they're the first to register, give them level 1000. */
1357 if (dict_size(nickserv_handle_dict
) == 1) {
1358 hi
->opserv_level
= 1000;
1359 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1362 /* Set their email address. */
1364 nickserv_set_email_addr(hi
, email_addr
);
1366 /* If they need to do email verification, tell them. */
1368 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1370 /* Set registering flag.. */
1371 user
->modes
|= FLAGS_REGISTERING
;
1373 if (nickserv_conf
.sync_log
) {
1374 cryptpass(password
, syncpass
);
1376 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1377 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1380 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1383 /* this wont work if email is required .. */
1384 process_adduser_pending(user
);
1389 static NICKSERV_FUNC(cmd_oregister
)
1392 struct userNode
*settee
;
1393 struct handle_info
*hi
;
1395 NICKSERV_MIN_PARMS(nickserv_conf
.email_required
? 4 : 3);
1397 if (!is_valid_handle(argv
[1])) {
1398 reply("NSMSG_BAD_HANDLE", argv
[1]);
1402 if (nickserv_conf
.email_required
) {
1403 if (!valid_email(argv
[4])) {
1404 reply("NSMSG_BAD_EMAIL_ADDR");
1409 if (strchr(argv
[3], '@')) {
1410 mask
= canonicalize_hostmask(strdup(argv
[3]));
1412 settee
= GetUserH(nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1414 reply("MSG_NICK_UNKNOWN", nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1421 } else if ((settee
= GetUserH(argv
[3]))) {
1422 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1424 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1427 if (settee
&& settee
->handle_info
) {
1428 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1432 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1433 if (nickserv_conf
.email_required
) {
1434 nickserv_set_email_addr(hi
, argv
[4]);
1435 if (nickserv_conf
.sync_log
)
1436 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, argv
[4], user
->info
);
1441 string_list_append(hi
->masks
, mask
);
1445 static NICKSERV_FUNC(cmd_handleinfo
)
1448 unsigned int i
, pos
=0, herelen
;
1449 struct userNode
*target
, *next_un
;
1450 struct handle_info
*hi
;
1451 const char *nsmsg_none
;
1454 if (!(hi
= user
->handle_info
)) {
1455 reply("NSMSG_MUST_AUTH");
1458 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1462 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1463 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1465 #ifdef WITH_PROTOCOL_BAHAMUT
1466 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1468 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1471 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1472 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1474 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1477 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1478 if (HANDLE_FLAGGED(hi
, FROZEN
))
1479 reply("NSMSG_HANDLEINFO_VACATION");
1481 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1482 struct do_not_register
*dnr
;
1483 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1484 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1485 if (!oper_outranks(user
, hi
))
1487 } else if (hi
!= user
->handle_info
) {
1488 reply("NSMSG_HANDLEINFO_END");
1492 if (nickserv_conf
.email_enabled
)
1493 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1497 switch (hi
->cookie
->type
) {
1498 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1499 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1500 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1501 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1502 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1508 unsigned long flen
= 1;
1509 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1511 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1512 if (hi
->flags
& 1 << i
)
1513 flags
[flen
++] = handle_flags
[i
];
1515 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1517 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1520 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1521 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1522 || (hi
->opserv_level
> 0)) {
1523 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1526 if (IsHelping(user
) || IsOper(user
))
1531 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1532 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1537 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1539 if (hi
->last_quit_host
[0])
1540 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1542 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1544 if (nickserv_conf
.disable_nicks
) {
1545 /* nicks disabled; don't show anything about registered nicks */
1546 } else if (hi
->nicks
) {
1547 struct nick_info
*ni
, *next_ni
;
1548 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1549 herelen
= strlen(ni
->nick
);
1550 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1552 goto print_nicks_buff
;
1556 memcpy(buff
+pos
, ni
->nick
, herelen
);
1557 pos
+= herelen
; buff
[pos
++] = ' ';
1561 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1566 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1569 if (hi
->masks
->used
) {
1570 for (i
=0; i
< hi
->masks
->used
; i
++) {
1571 herelen
= strlen(hi
->masks
->list
[i
]);
1572 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1574 goto print_mask_buff
;
1576 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1577 pos
+= herelen
; buff
[pos
++] = ' ';
1578 if (i
+1 == hi
->masks
->used
) {
1581 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1586 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1590 struct userData
*channel
, *next
;
1593 for (channel
= hi
->channels
; channel
; channel
= next
) {
1594 next
= channel
->u_next
;
1595 name
= channel
->channel
->channel
->name
;
1596 herelen
= strlen(name
);
1597 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1599 goto print_chans_buff
;
1601 if (IsUserSuspended(channel
))
1603 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1607 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1612 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1615 for (target
= hi
->users
; target
; target
= next_un
) {
1616 herelen
= strlen(target
->nick
);
1617 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1619 goto print_cnick_buff
;
1621 next_un
= target
->next_authed
;
1623 memcpy(buff
+pos
, target
->nick
, herelen
);
1624 pos
+= herelen
; buff
[pos
++] = ' ';
1628 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1633 reply("NSMSG_HANDLEINFO_END");
1637 static NICKSERV_FUNC(cmd_userinfo
)
1639 struct userNode
*target
;
1641 NICKSERV_MIN_PARMS(2);
1642 if (!(target
= GetUserH(argv
[1]))) {
1643 reply("MSG_NICK_UNKNOWN", argv
[1]);
1646 if (target
->handle_info
)
1647 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1649 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1653 static NICKSERV_FUNC(cmd_nickinfo
)
1655 struct nick_info
*ni
;
1657 NICKSERV_MIN_PARMS(2);
1658 if (!(ni
= get_nick_info(argv
[1]))) {
1659 reply("MSG_NICK_UNKNOWN", argv
[1]);
1662 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1666 static NICKSERV_FUNC(cmd_rename_handle
)
1668 struct handle_info
*hi
;
1669 struct userNode
*uNode
;
1670 char msgbuf
[MAXLEN
], *old_handle
;
1673 NICKSERV_MIN_PARMS(3);
1674 if (!(hi
= get_victim_oper(user
, argv
[1])))
1676 if (!is_valid_handle(argv
[2])) {
1677 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1680 if (get_handle_info(argv
[2])) {
1681 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1684 if(strlen(argv
[2]) > 15)
1686 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1690 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1691 hi
->handle
= strdup(argv
[2]);
1692 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1693 for (nn
=0; nn
<rf_list_used
; nn
++)
1694 rf_list
[nn
](hi
, old_handle
);
1695 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1698 if (nickserv_conf
.sync_log
) {
1699 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1700 irc_rename(uNode
, hi
->handle
);
1702 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1705 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1706 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1711 static failpw_func_t
*failpw_func_list
;
1712 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1715 reg_failpw_func(failpw_func_t func
)
1717 if (failpw_func_used
== failpw_func_size
) {
1718 if (failpw_func_size
) {
1719 failpw_func_size
<<= 1;
1720 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1722 failpw_func_size
= 8;
1723 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1726 failpw_func_list
[failpw_func_used
++] = func
;
1730 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1732 * called by nefariouses enhanced AC login-on-connect code
1735 struct handle_info
*loc_auth(char *handle
, char *password
)
1737 int pw_arg
, used
, maxlogins
;
1740 struct handle_info
*hi
;
1741 struct userNode
*other
;
1743 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1749 /* We don't know the users hostname, or anything because they
1750 * havn't registered yet. So we can only allow LOC if your
1751 * account has *@* as a hostmask.
1753 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1755 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1764 /* Responses from here on look up the language used by the handle they asked about. */
1765 if (!checkpass(password
, hi
->passwd
)) {
1768 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1771 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1772 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1773 if (++used
>= maxlogins
) {
1780 static NICKSERV_FUNC(cmd_auth
)
1782 int pw_arg
, used
, maxlogins
;
1783 struct handle_info
*hi
;
1785 struct userNode
*other
;
1787 if (user
->handle_info
) {
1788 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1791 if (IsStamped(user
)) {
1792 /* Unauthenticated users might still have been stamped
1793 previously and could therefore have a hidden host;
1794 do not allow them to authenticate. */
1795 reply("NSMSG_STAMPED_AUTH");
1799 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1801 } else if (argc
== 2) {
1802 if (nickserv_conf
.disable_nicks
) {
1803 if (!(hi
= get_handle_info(user
->nick
))) {
1804 reply("NSMSG_HANDLE_NOT_FOUND");
1808 /* try to look up their handle from their nick */
1809 struct nick_info
*ni
;
1810 ni
= get_nick_info(user
->nick
);
1812 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1819 reply("MSG_MISSING_PARAMS", argv
[0]);
1820 svccmd_send_help_brief(user
, nickserv
, cmd
);
1824 reply("NSMSG_HANDLE_NOT_FOUND");
1827 /* Responses from here on look up the language used by the handle they asked about. */
1828 passwd
= argv
[pw_arg
];
1829 if (!valid_user_for(user
, hi
)) {
1830 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1831 send_message_type(4, user
, cmd
->parent
->bot
,
1832 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1835 send_message_type(4, user
, cmd
->parent
->bot
,
1836 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1838 argv
[pw_arg
] = "BADMASK";
1841 if (!checkpass(passwd
, hi
->passwd
)) {
1843 send_message_type(4, user
, cmd
->parent
->bot
,
1844 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1845 argv
[pw_arg
] = "BADPASS";
1846 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1847 if (nickserv_conf
.autogag_enabled
) {
1848 if (!user
->auth_policer
.params
) {
1849 user
->auth_policer
.last_req
= now
;
1850 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1852 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1854 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1855 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1856 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1858 argv
[pw_arg
] = "GAGGED";
1863 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1864 send_message_type(4, user
, cmd
->parent
->bot
,
1865 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1866 argv
[pw_arg
] = "SUSPENDED";
1869 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1870 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1871 if (++used
>= maxlogins
) {
1872 send_message_type(4, user
, cmd
->parent
->bot
,
1873 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1875 argv
[pw_arg
] = "MAXLOGINS";
1880 set_user_handle_info(user
, hi
, 1);
1881 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1882 reply("NSMSG_PLEASE_SET_EMAIL");
1883 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1884 reply("NSMSG_WEAK_PASSWORD");
1885 if (hi
->passwd
[0] != '$')
1886 cryptpass(passwd
, hi
->passwd
);
1888 /* If a channel was waiting for this user to auth,
1889 * finish adding them */
1890 process_adduser_pending(user
);
1892 reply("NSMSG_AUTH_SUCCESS");
1895 /* Set +x if autohide is on */
1896 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
1897 irc_umode(user
, "+x");
1899 if(!IsOper(user
)) /* If they arnt already opered.. */
1901 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
1902 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
1904 irc_umode(user
,nickserv_conf
.auto_admin
);
1905 reply("NSMSG_AUTO_OPER_ADMIN");
1907 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
1909 irc_umode(user
,nickserv_conf
.auto_oper
);
1910 reply("NSMSG_AUTO_OPER");
1914 /* Wipe out the pass for the logs */
1915 argv
[pw_arg
] = "****";
1919 static allowauth_func_t
*allowauth_func_list
;
1920 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1923 reg_allowauth_func(allowauth_func_t func
)
1925 if (allowauth_func_used
== allowauth_func_size
) {
1926 if (allowauth_func_size
) {
1927 allowauth_func_size
<<= 1;
1928 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1930 allowauth_func_size
= 8;
1931 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1934 allowauth_func_list
[allowauth_func_used
++] = func
;
1937 static NICKSERV_FUNC(cmd_allowauth
)
1939 struct userNode
*target
;
1940 struct handle_info
*hi
;
1943 NICKSERV_MIN_PARMS(2);
1944 if (!(target
= GetUserH(argv
[1]))) {
1945 reply("MSG_NICK_UNKNOWN", argv
[1]);
1948 if (target
->handle_info
) {
1949 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1952 if (IsStamped(target
)) {
1953 /* Unauthenticated users might still have been stamped
1954 previously and could therefore have a hidden host;
1955 do not allow them to authenticate to an account. */
1956 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1961 else if (!(hi
= get_handle_info(argv
[2]))) {
1962 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1966 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1967 reply("MSG_USER_OUTRANKED", hi
->handle
);
1970 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1971 || (hi
->opserv_level
> 0))
1972 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1973 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1976 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1977 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1978 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1979 if (nickserv_conf
.email_enabled
)
1980 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1982 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1983 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1985 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1987 for (n
=0; n
<allowauth_func_used
; n
++)
1988 allowauth_func_list
[n
](user
, target
, hi
);
1992 static NICKSERV_FUNC(cmd_authcookie
)
1994 struct handle_info
*hi
;
1996 NICKSERV_MIN_PARMS(2);
1997 if (user
->handle_info
) {
1998 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2001 if (IsStamped(user
)) {
2002 /* Unauthenticated users might still have been stamped
2003 previously and could therefore have a hidden host;
2004 do not allow them to authenticate to an account. */
2005 reply("NSMSG_STAMPED_AUTHCOOKIE");
2008 if (!(hi
= get_handle_info(argv
[1]))) {
2009 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2012 if (!hi
->email_addr
) {
2013 reply("MSG_SET_EMAIL_ADDR");
2016 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2020 static NICKSERV_FUNC(cmd_delcookie
)
2022 struct handle_info
*hi
;
2024 hi
= user
->handle_info
;
2026 reply("NSMSG_NO_COOKIE");
2029 switch (hi
->cookie
->type
) {
2032 reply("NSMSG_MUST_TIME_OUT");
2035 nickserv_eat_cookie(hi
->cookie
);
2036 reply("NSMSG_ATE_COOKIE");
2042 static NICKSERV_FUNC(cmd_odelcookie
)
2044 struct handle_info
*hi
;
2046 NICKSERV_MIN_PARMS(2);
2048 if (!(hi
= get_victim_oper(user
, argv
[1])))
2052 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2056 nickserv_eat_cookie(hi
->cookie
);
2057 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2062 static NICKSERV_FUNC(cmd_resetpass
)
2064 struct handle_info
*hi
;
2065 char crypted
[MD5_CRYPT_LENGTH
];
2068 NICKSERV_MIN_PARMS(3);
2069 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2073 if (user
->handle_info
) {
2074 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2077 if (IsStamped(user
)) {
2078 /* Unauthenticated users might still have been stamped
2079 previously and could therefore have a hidden host;
2080 do not allow them to activate an account. */
2081 reply("NSMSG_STAMPED_RESETPASS");
2084 if (!(hi
= get_handle_info(argv
[1]))) {
2085 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2088 if (!hi
->email_addr
) {
2089 reply("MSG_SET_EMAIL_ADDR");
2092 cryptpass(argv
[2], crypted
);
2094 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2098 static NICKSERV_FUNC(cmd_cookie
)
2100 struct handle_info
*hi
;
2103 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2106 NICKSERV_MIN_PARMS(3);
2107 if (!(hi
= get_handle_info(argv
[1]))) {
2108 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2114 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2115 reply("NSMSG_HANDLE_SUSPENDED");
2120 reply("NSMSG_NO_COOKIE");
2124 /* Check validity of operation before comparing cookie to
2125 * prohibit guessing by authed users. */
2126 if (user
->handle_info
2127 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2128 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2129 reply("NSMSG_CANNOT_COOKIE");
2133 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2134 reply("NSMSG_BAD_COOKIE");
2138 switch (hi
->cookie
->type
) {
2140 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2141 set_user_handle_info(user
, hi
, 1);
2142 reply("NSMSG_HANDLE_ACTIVATED");
2143 if (nickserv_conf
.sync_log
)
2144 SyncLog("ACCOUNTACC %s", hi
->handle
);
2146 case PASSWORD_CHANGE
:
2147 set_user_handle_info(user
, hi
, 1);
2148 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2149 reply("NSMSG_PASSWORD_CHANGED");
2150 if (nickserv_conf
.sync_log
)
2151 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2154 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2156 * This should only happen if an OREGISTER was sent. Require
2157 * email must be enabled! - SiRVulcaN
2159 if (nickserv_conf
.sync_log
)
2160 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2162 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2163 reply("NSMSG_EMAIL_CHANGED");
2164 if (nickserv_conf
.sync_log
)
2165 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2168 set_user_handle_info(user
, hi
, 1);
2169 reply("NSMSG_AUTH_SUCCESS");
2172 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2173 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2177 nickserv_eat_cookie(hi
->cookie
);
2179 process_adduser_pending(user
);
2184 static NICKSERV_FUNC(cmd_oregnick
) {
2186 struct handle_info
*target
;
2187 struct nick_info
*ni
;
2189 NICKSERV_MIN_PARMS(3);
2190 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2193 if (!is_registerable_nick(nick
)) {
2194 reply("NSMSG_BAD_NICK", nick
);
2197 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2199 reply("NSMSG_NICK_EXISTS", nick
);
2202 register_nick(nick
, target
);
2203 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2207 static NICKSERV_FUNC(cmd_regnick
) {
2209 struct nick_info
*ni
;
2211 if (!is_registerable_nick(user
->nick
)) {
2212 reply("NSMSG_BAD_NICK", user
->nick
);
2215 /* count their nicks, see if it's too many */
2216 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2217 if (n
>= nickserv_conf
.nicks_per_handle
) {
2218 reply("NSMSG_TOO_MANY_NICKS");
2221 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2223 reply("NSMSG_NICK_EXISTS", user
->nick
);
2226 register_nick(user
->nick
, user
->handle_info
);
2227 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2231 static NICKSERV_FUNC(cmd_pass
)
2233 struct handle_info
*hi
;
2234 const char *old_pass
, *new_pass
;
2236 NICKSERV_MIN_PARMS(3);
2237 hi
= user
->handle_info
;
2241 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2242 if (!checkpass(old_pass
, hi
->passwd
)) {
2243 argv
[1] = "BADPASS";
2244 reply("NSMSG_PASSWORD_INVALID");
2247 cryptpass(new_pass
, hi
->passwd
);
2248 if (nickserv_conf
.sync_log
)
2249 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2251 reply("NSMSG_PASS_SUCCESS");
2256 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2259 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2260 for (i
=0; i
<hi
->masks
->used
; i
++) {
2261 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2262 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2267 string_list_append(hi
->masks
, new_mask
);
2268 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2272 static NICKSERV_FUNC(cmd_addmask
)
2275 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2276 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2280 if (!is_gline(argv
[1])) {
2281 reply("NSMSG_MASK_INVALID", argv
[1]);
2284 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2288 static NICKSERV_FUNC(cmd_oaddmask
)
2290 struct handle_info
*hi
;
2292 NICKSERV_MIN_PARMS(3);
2293 if (!(hi
= get_victim_oper(user
, argv
[1])))
2295 return nickserv_addmask(user
, hi
, argv
[2]);
2299 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2302 for (i
=0; i
<hi
->masks
->used
; i
++) {
2303 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2304 char *old_mask
= hi
->masks
->list
[i
];
2305 if (hi
->masks
->used
== 1) {
2306 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2309 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2310 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2315 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2319 static NICKSERV_FUNC(cmd_delmask
)
2321 NICKSERV_MIN_PARMS(2);
2322 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2325 static NICKSERV_FUNC(cmd_odelmask
)
2327 struct handle_info
*hi
;
2328 NICKSERV_MIN_PARMS(3);
2329 if (!(hi
= get_victim_oper(user
, argv
[1])))
2331 return nickserv_delmask(user
, hi
, argv
[2]);
2335 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2336 unsigned int nn
, add
= 1, pos
;
2337 unsigned long added
, removed
, flag
;
2339 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2341 case '+': add
= 1; break;
2342 case '-': add
= 0; break;
2344 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2345 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2348 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2349 /* cheesy avoidance of looking up the flag name.. */
2350 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2353 flag
= 1 << (pos
- 1);
2355 added
|= flag
, removed
&= ~flag
;
2357 removed
|= flag
, added
&= ~flag
;
2362 *premoved
= removed
;
2367 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2369 unsigned long before
, after
, added
, removed
;
2370 struct userNode
*uNode
;
2372 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2373 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2375 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2376 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2378 /* Strip helping flag if they're only a support helper and not
2379 * currently in #support. */
2380 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2381 struct channelList
*schannels
;
2383 schannels
= chanserv_support_channels();
2384 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2385 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2386 if (GetUserMode(schannels
->list
[ii
], uNode
))
2388 if (ii
< schannels
->used
)
2392 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2395 if (after
&& !before
) {
2396 /* Add user to current helper list. */
2397 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2398 userList_append(&curr_helpers
, uNode
);
2399 } else if (!after
&& before
) {
2400 /* Remove user from current helper list. */
2401 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2402 userList_remove(&curr_helpers
, uNode
);
2409 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2413 char *set_display
[] = {
2414 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2415 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2416 "FAKEHOST", "TITLE", "EPITHET"
2419 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2420 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2422 /* Do this so options are presented in a consistent order. */
2423 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2424 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2425 opt(user
, hi
, override
, 0, NULL
);
2426 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2429 static NICKSERV_FUNC(cmd_set
)
2431 struct handle_info
*hi
;
2434 hi
= user
->handle_info
;
2436 set_list(user
, hi
, 0);
2439 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2440 reply("NSMSG_INVALID_OPTION", argv
[1]);
2443 return opt(user
, hi
, 0, argc
-1, argv
+1);
2446 static NICKSERV_FUNC(cmd_oset
)
2448 struct handle_info
*hi
;
2451 NICKSERV_MIN_PARMS(2);
2453 if (!(hi
= get_victim_oper(user
, argv
[1])))
2457 set_list(user
, hi
, 0);
2461 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2462 reply("NSMSG_INVALID_OPTION", argv
[2]);
2466 return opt(user
, hi
, 1, argc
-2, argv
+2);
2469 static OPTION_FUNC(opt_info
)
2473 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2475 hi
->infoline
= NULL
;
2477 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2481 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2482 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2486 static OPTION_FUNC(opt_width
)
2489 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2491 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2492 hi
->screen_width
= MIN_LINE_SIZE
;
2493 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2494 hi
->screen_width
= MAX_LINE_SIZE
;
2496 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2500 static OPTION_FUNC(opt_tablewidth
)
2503 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2505 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2506 hi
->table_width
= MIN_LINE_SIZE
;
2507 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2508 hi
->table_width
= MAX_LINE_SIZE
;
2510 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2514 static OPTION_FUNC(opt_color
)
2517 if (enabled_string(argv
[1]))
2518 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2519 else if (disabled_string(argv
[1]))
2520 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2522 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2527 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2531 static OPTION_FUNC(opt_privmsg
)
2534 if (enabled_string(argv
[1]))
2535 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2536 else if (disabled_string(argv
[1]))
2537 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2539 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2544 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2548 static OPTION_FUNC(opt_autohide
)
2551 if (enabled_string(argv
[1]))
2552 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2553 else if (disabled_string(argv
[1]))
2554 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2556 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2561 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2565 static OPTION_FUNC(opt_style
)
2570 if (!irccasecmp(argv
[1], "Clean"))
2571 hi
->userlist_style
= HI_STYLE_CLEAN
;
2572 else if (!irccasecmp(argv
[1], "Advanced"))
2573 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2574 else /* Default to normal */
2575 hi
->userlist_style
= HI_STYLE_NORMAL
;
2576 } /* TODO: give error if unknow style is chosen */
2578 switch (hi
->userlist_style
) {
2579 case HI_STYLE_ADVANCED
:
2582 case HI_STYLE_CLEAN
:
2585 case HI_STYLE_NORMAL
:
2590 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2594 static OPTION_FUNC(opt_announcements
)
2599 if (enabled_string(argv
[1]))
2600 hi
->announcements
= 'y';
2601 else if (disabled_string(argv
[1]))
2602 hi
->announcements
= 'n';
2603 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2604 hi
->announcements
= '?';
2606 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2611 switch (hi
->announcements
) {
2612 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2613 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2614 case '?': choice
= "default"; break;
2615 default: choice
= "unknown"; break;
2617 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2621 static OPTION_FUNC(opt_password
)
2624 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2629 cryptpass(argv
[1], hi
->passwd
);
2631 if (nickserv_conf
.sync_log
)
2632 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2634 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2638 static OPTION_FUNC(opt_flags
)
2641 unsigned int ii
, flen
;
2644 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2649 nickserv_apply_flags(user
, hi
, argv
[1]);
2651 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2652 if (hi
->flags
& (1 << ii
))
2653 flags
[flen
++] = handle_flags
[ii
];
2656 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2658 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2662 static OPTION_FUNC(opt_email
)
2666 if (!valid_email(argv
[1])) {
2667 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2670 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2671 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2674 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2675 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2677 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2679 nickserv_set_email_addr(hi
, argv
[1]);
2681 nickserv_eat_cookie(hi
->cookie
);
2682 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2685 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2689 static OPTION_FUNC(opt_maxlogins
)
2691 unsigned char maxlogins
;
2693 maxlogins
= strtoul(argv
[1], NULL
, 0);
2694 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2695 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2698 hi
->maxlogins
= maxlogins
;
2700 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2701 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2705 static OPTION_FUNC(opt_language
)
2707 struct language
*lang
;
2709 lang
= language_find(argv
[1]);
2710 if (irccasecmp(lang
->name
, argv
[1]))
2711 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2712 hi
->language
= lang
;
2714 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2719 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2720 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2722 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2723 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2724 && (user
->handle_info
->opserv_level
< 1000))) {
2725 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2728 if ((user
->handle_info
->opserv_level
< new_level
)
2729 || ((user
->handle_info
->opserv_level
== new_level
)
2730 && (user
->handle_info
->opserv_level
< 1000))) {
2731 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2734 if (user
->handle_info
== target
) {
2735 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2738 if (target
->opserv_level
== new_level
)
2740 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2741 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2742 target
->opserv_level
= new_level
;
2746 static OPTION_FUNC(opt_level
)
2751 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2755 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2756 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2760 static OPTION_FUNC(opt_epithet
)
2762 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2765 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2769 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2773 if ((epithet
[0] == '*') && !epithet
[1])
2776 hi
->epithet
= strdup(epithet
);
2780 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2782 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2786 static OPTION_FUNC(opt_title
)
2790 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2792 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2797 if (strchr(title
, '.')) {
2798 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2801 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2802 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2803 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2808 if (!strcmp(title
, "*")) {
2809 hi
->fakehost
= NULL
;
2811 hi
->fakehost
= malloc(strlen(title
)+2);
2812 hi
->fakehost
[0] = '.';
2813 strcpy(hi
->fakehost
+1, title
);
2816 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2817 title
= hi
->fakehost
+ 1;
2821 title
= user_find_message(user
, "MSG_NONE");
2822 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2826 static OPTION_FUNC(opt_fakehost
)
2830 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2832 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2837 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2838 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2842 if (!strcmp(fake
, "*"))
2843 hi
->fakehost
= NULL
;
2845 hi
->fakehost
= strdup(fake
);
2846 fake
= hi
->fakehost
;
2849 fake
= generate_fakehost(hi
);
2851 fake
= user_find_message(user
, "MSG_NONE");
2852 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2856 static OPTION_FUNC(opt_note
)
2859 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2864 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
2869 if ((text
[0] == '*') && !text
[1])
2872 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
2877 send_message(user
, nickserv
, "NSMSG_SET_NOTE", hi
->note
->note
);
2881 static NICKSERV_FUNC(cmd_reclaim
)
2883 struct handle_info
*hi
;
2884 struct nick_info
*ni
;
2885 struct userNode
*victim
;
2887 NICKSERV_MIN_PARMS(2);
2888 hi
= user
->handle_info
;
2889 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2891 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2894 if (ni
->owner
!= user
->handle_info
) {
2895 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2898 victim
= GetUserH(ni
->nick
);
2900 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2903 if (victim
== user
) {
2904 reply("NSMSG_NICK_USER_YOU");
2907 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2908 switch (nickserv_conf
.reclaim_action
) {
2909 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2910 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2911 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2912 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2917 static NICKSERV_FUNC(cmd_unregnick
)
2920 struct handle_info
*hi
;
2921 struct nick_info
*ni
;
2923 hi
= user
->handle_info
;
2924 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2925 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2927 reply("NSMSG_UNKNOWN_NICK", nick
);
2930 if (hi
!= ni
->owner
) {
2931 reply("NSMSG_NOT_YOUR_NICK", nick
);
2934 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2939 static NICKSERV_FUNC(cmd_ounregnick
)
2941 struct nick_info
*ni
;
2943 NICKSERV_MIN_PARMS(2);
2944 if (!(ni
= get_nick_info(argv
[1]))) {
2945 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2948 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2949 reply("MSG_USER_OUTRANKED", ni
->nick
);
2952 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2957 static NICKSERV_FUNC(cmd_unregister
)
2959 struct handle_info
*hi
;
2962 NICKSERV_MIN_PARMS(2);
2963 hi
= user
->handle_info
;
2966 if (checkpass(passwd
, hi
->passwd
)) {
2967 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2970 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2971 reply("NSMSG_PASSWORD_INVALID");
2976 static NICKSERV_FUNC(cmd_ounregister
)
2978 struct handle_info
*hi
;
2980 NICKSERV_MIN_PARMS(2);
2981 if (!(hi
= get_victim_oper(user
, argv
[1])))
2983 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2987 static NICKSERV_FUNC(cmd_status
)
2989 if (nickserv_conf
.disable_nicks
) {
2990 reply("NSMSG_GLOBAL_STATS_NONICK",
2991 dict_size(nickserv_handle_dict
));
2993 if (user
->handle_info
) {
2995 struct nick_info
*ni
;
2996 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2997 reply("NSMSG_HANDLE_STATS", cnt
);
2999 reply("NSMSG_HANDLE_NONE");
3001 reply("NSMSG_GLOBAL_STATS",
3002 dict_size(nickserv_handle_dict
),
3003 dict_size(nickserv_nick_dict
));
3008 static NICKSERV_FUNC(cmd_ghost
)
3010 struct userNode
*target
;
3011 char reason
[MAXLEN
];
3013 NICKSERV_MIN_PARMS(2);
3014 if (!(target
= GetUserH(argv
[1]))) {
3015 reply("MSG_NICK_UNKNOWN", argv
[1]);
3018 if (target
== user
) {
3019 reply("NSMSG_CANNOT_GHOST_SELF");
3022 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3023 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3026 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3027 DelUser(target
, nickserv
, 1, reason
);
3028 reply("NSMSG_GHOST_KILLED", argv
[1]);
3032 static NICKSERV_FUNC(cmd_vacation
)
3034 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3035 reply("NSMSG_ON_VACATION");
3040 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3042 struct handle_info
*hi
;
3045 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3047 #ifdef WITH_PROTOCOL_BAHAMUT
3050 saxdb_start_record(ctx
, iter_key(it
), 0);
3051 if (hi
->announcements
!= '?') {
3052 flags
[0] = hi
->announcements
;
3054 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3057 struct handle_cookie
*cookie
= hi
->cookie
;
3060 switch (cookie
->type
) {
3061 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3062 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3063 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3064 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3065 default: type
= NULL
; break;
3068 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3069 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3070 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3072 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3073 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3074 saxdb_end_record(ctx
);
3078 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3080 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3082 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3083 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3084 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3085 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3086 saxdb_end_record(ctx
);
3090 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3094 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3095 if (hi
->flags
& (1 << ii
))
3096 flags
[flen
++] = handle_flags
[ii
];
3098 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3100 #ifdef WITH_PROTOCOL_BAHAMUT
3101 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3104 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3105 if (hi
->last_quit_host
[0])
3106 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3107 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3108 if (hi
->masks
->used
)
3109 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3111 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3113 struct string_list
*slist
;
3114 struct nick_info
*ni
;
3116 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3117 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3118 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3122 if (hi
->opserv_level
)
3123 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3124 if (hi
->language
!= lang_C
)
3125 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3126 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3127 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3128 if (hi
->screen_width
)
3129 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3130 if (hi
->table_width
)
3131 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3132 flags
[0] = hi
->userlist_style
;
3134 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3135 saxdb_end_record(ctx
);
3140 static handle_merge_func_t
*handle_merge_func_list
;
3141 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3144 reg_handle_merge_func(handle_merge_func_t func
)
3146 if (handle_merge_func_used
== handle_merge_func_size
) {
3147 if (handle_merge_func_size
) {
3148 handle_merge_func_size
<<= 1;
3149 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3151 handle_merge_func_size
= 8;
3152 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3155 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3158 static NICKSERV_FUNC(cmd_merge
)
3160 struct handle_info
*hi_from
, *hi_to
;
3161 struct userNode
*last_user
;
3162 struct userData
*cList
, *cListNext
;
3163 unsigned int ii
, jj
, n
;
3164 char buffer
[MAXLEN
];
3166 NICKSERV_MIN_PARMS(3);
3168 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3170 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3172 if (hi_to
== hi_from
) {
3173 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3177 for (n
=0; n
<handle_merge_func_used
; n
++)
3178 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3180 /* Append "from" handle's nicks to "to" handle's nick list. */
3182 struct nick_info
*last_ni
;
3183 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3184 last_ni
->next
= hi_from
->nicks
;
3186 while (hi_from
->nicks
) {
3187 hi_from
->nicks
->owner
= hi_to
;
3188 hi_from
->nicks
= hi_from
->nicks
->next
;
3191 /* Merge the hostmasks. */
3192 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3193 char *mask
= hi_from
->masks
->list
[ii
];
3194 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3195 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3197 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3198 string_list_append(hi_to
->masks
, strdup(mask
));
3201 /* Merge the lists of authed users. */
3203 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3204 last_user
->next_authed
= hi_from
->users
;
3206 hi_to
->users
= hi_from
->users
;
3208 /* Repoint the old "from" handle's users. */
3209 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3210 last_user
->handle_info
= hi_to
;
3212 hi_from
->users
= NULL
;
3214 /* Merge channel userlists. */
3215 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3216 struct userData
*cList2
;
3217 cListNext
= cList
->u_next
;
3218 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3219 if (cList
->channel
== cList2
->channel
)
3221 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3222 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
);
3223 /* keep cList2 in hi_to; remove cList from hi_from */
3224 del_channel_user(cList
, 1);
3227 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
);
3228 /* remove the lower-ranking cList2 from hi_to */
3229 del_channel_user(cList2
, 1);
3231 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3233 /* cList needs to be moved from hi_from to hi_to */
3234 cList
->handle
= hi_to
;
3235 /* Remove from linked list for hi_from */
3236 assert(!cList
->u_prev
);
3237 hi_from
->channels
= cList
->u_next
;
3239 cList
->u_next
->u_prev
= cList
->u_prev
;
3240 /* Add to linked list for hi_to */
3241 cList
->u_prev
= NULL
;
3242 cList
->u_next
= hi_to
->channels
;
3243 if (hi_to
->channels
)
3244 hi_to
->channels
->u_prev
= cList
;
3245 hi_to
->channels
= cList
;
3249 /* Do they get an OpServ level promotion? */
3250 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3251 hi_to
->opserv_level
= hi_from
->opserv_level
;
3253 /* What about last seen time? */
3254 if (hi_from
->lastseen
> hi_to
->lastseen
)
3255 hi_to
->lastseen
= hi_from
->lastseen
;
3257 /* Does a fakehost carry over? (This intentionally doesn't set it
3258 * for users previously attached to hi_to. They'll just have to
3261 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3262 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3264 /* Notify of success. */
3265 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3266 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3267 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3269 /* Unregister the "from" handle. */
3270 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3275 struct nickserv_discrim
{
3276 unsigned int limit
, min_level
, max_level
;
3277 unsigned long flags_on
, flags_off
;
3278 time_t min_registered
, max_registered
;
3280 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3281 const char *nickmask
;
3282 const char *hostmask
;
3283 const char *handlemask
;
3284 const char *emailmask
;
3287 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3289 struct discrim_apply_info
{
3290 struct nickserv_discrim
*discrim
;
3291 discrim_search_func func
;
3292 struct userNode
*source
;
3293 unsigned int matched
;
3296 static struct nickserv_discrim
*
3297 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3300 struct nickserv_discrim
*discrim
;
3302 discrim
= malloc(sizeof(*discrim
));
3303 memset(discrim
, 0, sizeof(*discrim
));
3304 discrim
->min_level
= 0;
3305 discrim
->max_level
= ~0;
3306 discrim
->limit
= 50;
3307 discrim
->min_registered
= 0;
3308 discrim
->max_registered
= INT_MAX
;
3309 discrim
->lastseen
= now
;
3311 for (i
=0; i
<argc
; i
++) {
3312 if (i
== argc
- 1) {
3313 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3316 if (!irccasecmp(argv
[i
], "limit")) {
3317 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3318 } else if (!irccasecmp(argv
[i
], "flags")) {
3319 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3320 } else if (!irccasecmp(argv
[i
], "registered")) {
3321 const char *cmp
= argv
[++i
];
3322 if (cmp
[0] == '<') {
3323 if (cmp
[1] == '=') {
3324 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3326 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3328 } else if (cmp
[0] == '=') {
3329 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3330 } else if (cmp
[0] == '>') {
3331 if (cmp
[1] == '=') {
3332 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3334 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3337 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3339 } else if (!irccasecmp(argv
[i
], "seen")) {
3340 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3341 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3342 discrim
->nickmask
= argv
[++i
];
3343 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3345 if (!irccasecmp(argv
[i
], "exact")) {
3346 if (i
== argc
- 1) {
3347 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3350 discrim
->hostmask_type
= EXACT
;
3351 } else if (!irccasecmp(argv
[i
], "subset")) {
3352 if (i
== argc
- 1) {
3353 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3356 discrim
->hostmask_type
= SUBSET
;
3357 } else if (!irccasecmp(argv
[i
], "superset")) {
3358 if (i
== argc
- 1) {
3359 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3362 discrim
->hostmask_type
= SUPERSET
;
3363 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3364 if (i
== argc
- 1) {
3365 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3368 discrim
->hostmask_type
= LASTQUIT
;
3371 discrim
->hostmask_type
= SUPERSET
;
3373 discrim
->hostmask
= argv
[++i
];
3374 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3375 if (!irccasecmp(argv
[++i
], "*")) {
3376 discrim
->handlemask
= 0;
3378 discrim
->handlemask
= argv
[i
];
3380 } else if (!irccasecmp(argv
[i
], "email")) {
3381 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3382 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3384 } else if (!irccasecmp(argv
[++i
], "*")) {
3385 discrim
->emailmask
= 0;
3387 discrim
->emailmask
= argv
[i
];
3389 } else if (!irccasecmp(argv
[i
], "access")) {
3390 const char *cmp
= argv
[++i
];
3391 if (cmp
[0] == '<') {
3392 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3393 if (cmp
[1] == '=') {
3394 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3396 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3398 } else if (cmp
[0] == '=') {
3399 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3400 } else if (cmp
[0] == '>') {
3401 if (cmp
[1] == '=') {
3402 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3404 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3407 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3410 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3421 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3423 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3424 || (discrim
->flags_off
& hi
->flags
)
3425 || (discrim
->min_registered
> hi
->registered
)
3426 || (discrim
->max_registered
< hi
->registered
)
3427 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3428 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3429 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3430 || (discrim
->min_level
> hi
->opserv_level
)
3431 || (discrim
->max_level
< hi
->opserv_level
)) {
3434 if (discrim
->hostmask
) {
3436 for (i
=0; i
<hi
->masks
->used
; i
++) {
3437 const char *mask
= hi
->masks
->list
[i
];
3438 if ((discrim
->hostmask_type
== SUBSET
)
3439 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3440 else if ((discrim
->hostmask_type
== EXACT
)
3441 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3442 else if ((discrim
->hostmask_type
== SUPERSET
)
3443 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3444 else if ((discrim
->hostmask_type
== LASTQUIT
)
3445 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3447 if (i
==hi
->masks
->used
) return 0;
3449 if (discrim
->nickmask
) {
3450 struct nick_info
*nick
= hi
->nicks
;
3452 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3455 if (!nick
) return 0;
3461 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3463 dict_iterator_t it
, next
;
3464 unsigned int matched
;
3466 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3467 it
&& (matched
< discrim
->limit
);
3469 next
= iter_next(it
);
3470 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3471 dsf(source
, iter_data(it
));
3479 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3481 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3485 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3490 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3492 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3493 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3497 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3499 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3500 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3501 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3502 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3503 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3507 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3509 struct handle_info_list hil
;
3510 struct helpfile_table tbl
;
3515 memset(&hil
, 0, sizeof(hil
));
3516 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3517 struct handle_info
*hi
= iter_data(it
);
3518 if (hi
->opserv_level
)
3519 handle_info_list_append(&hil
, hi
);
3521 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3522 tbl
.length
= hil
.used
+ 1;
3524 tbl
.flags
= TABLE_NO_FREE
;
3525 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3526 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3529 for (ii
= 0; ii
< hil
.used
; ) {
3530 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3531 ary
[0] = hil
.list
[ii
]->handle
;
3532 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3533 tbl
.contents
[++ii
] = ary
;
3535 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3536 reply("MSG_MATCH_COUNT", hil
.used
);
3537 for (ii
= 0; ii
< hil
.used
; ii
++)
3538 free(tbl
.contents
[ii
]);
3543 static NICKSERV_FUNC(cmd_search
)
3545 struct nickserv_discrim
*discrim
;
3546 discrim_search_func action
;
3547 struct svccmd
*subcmd
;
3548 unsigned int matches
;
3551 NICKSERV_MIN_PARMS(3);
3552 sprintf(buf
, "search %s", argv
[1]);
3553 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3554 if (!irccasecmp(argv
[1], "print"))
3555 action
= search_print_func
;
3556 else if (!irccasecmp(argv
[1], "count"))
3557 action
= search_count_func
;
3558 else if (!irccasecmp(argv
[1], "unregister"))
3559 action
= search_unregister_func
;
3561 reply("NSMSG_INVALID_ACTION", argv
[1]);
3565 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3568 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3572 if (action
== search_print_func
)
3573 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3574 else if (action
== search_count_func
)
3575 discrim
->limit
= INT_MAX
;
3577 matches
= nickserv_discrim_search(discrim
, action
, user
);
3580 reply("MSG_MATCH_COUNT", matches
);
3582 reply("MSG_NO_MATCHES");
3588 static MODCMD_FUNC(cmd_checkpass
)
3590 struct handle_info
*hi
;
3592 NICKSERV_MIN_PARMS(3);
3593 if (!(hi
= get_handle_info(argv
[1]))) {
3594 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3597 if (checkpass(argv
[2], hi
->passwd
))
3598 reply("CHECKPASS_YES");
3600 reply("CHECKPASS_NO");
3606 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3609 struct string_list
*masks
, *slist
;
3610 struct handle_info
*hi
;
3611 struct userNode
*authed_users
;
3612 struct userData
*channels
;
3613 unsigned long int id
;
3616 char *setter
, *note
;
3619 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3620 id
= str
? strtoul(str
, NULL
, 0) : 0;
3621 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3623 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3626 if ((hi
= get_handle_info(handle
))) {
3627 authed_users
= hi
->users
;
3628 channels
= hi
->channels
;
3630 hi
->channels
= NULL
;
3631 dict_remove(nickserv_handle_dict
, hi
->handle
);
3633 authed_users
= NULL
;
3636 hi
= register_handle(handle
, str
, id
);
3638 hi
->users
= authed_users
;
3639 while (authed_users
) {
3640 authed_users
->handle_info
= hi
;
3641 authed_users
= authed_users
->next_authed
;
3644 hi
->channels
= channels
;
3645 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3646 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3647 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3648 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3649 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3650 hi
->language
= language_find(str
? str
: "C");
3651 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3652 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3653 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3655 hi
->infoline
= strdup(str
);
3656 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3657 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3658 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3659 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3660 /* We want to read the nicks even if disable_nicks is set. This is so
3661 * that we don't lose the nick data entirely. */
3662 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3664 for (ii
=0; ii
<slist
->used
; ii
++)
3665 register_nick(slist
->list
[ii
], hi
);
3667 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3669 for (ii
=0; str
[ii
]; ii
++)
3670 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3672 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3673 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3674 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3675 hi
->announcements
= str
? str
[0] : '?';
3676 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3677 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3678 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3679 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3680 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3682 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3684 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3685 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3687 nickserv_set_email_addr(hi
, str
);
3688 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3690 hi
->epithet
= strdup(str
);
3691 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3693 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3694 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3695 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3696 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3697 if (setter
&& date
&& note
)
3699 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3704 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3706 hi
->fakehost
= strdup(str
);
3707 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3709 const char *data
, *type
, *expires
, *cookie_str
;
3710 struct handle_cookie
*cookie
;
3712 cookie
= calloc(1, sizeof(*cookie
));
3713 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3714 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3715 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3716 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3717 if (!type
|| !expires
|| !cookie_str
) {
3718 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3721 if (!irccasecmp(type
, KEY_ACTIVATION
))
3722 cookie
->type
= ACTIVATION
;
3723 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3724 cookie
->type
= PASSWORD_CHANGE
;
3725 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3726 cookie
->type
= EMAIL_CHANGE
;
3727 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3728 cookie
->type
= ALLOWAUTH
;
3730 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3733 cookie
->expires
= strtoul(expires
, NULL
, 0);
3734 if (cookie
->expires
< now
)
3737 cookie
->data
= strdup(data
);
3738 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3742 nickserv_bake_cookie(cookie
);
3744 nickserv_free_cookie(cookie
);
3749 nickserv_saxdb_read(dict_t db
) {
3751 struct record_data
*rd
;
3753 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3755 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3760 static NICKSERV_FUNC(cmd_mergedb
)
3762 struct timeval start
, stop
;
3765 NICKSERV_MIN_PARMS(2);
3766 gettimeofday(&start
, NULL
);
3767 if (!(db
= parse_database(argv
[1]))) {
3768 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3771 nickserv_saxdb_read(db
);
3773 gettimeofday(&stop
, NULL
);
3774 stop
.tv_sec
-= start
.tv_sec
;
3775 stop
.tv_usec
-= start
.tv_usec
;
3776 if (stop
.tv_usec
< 0) {
3778 stop
.tv_usec
+= 1000000;
3780 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3785 expire_handles(UNUSED_ARG(void *data
))
3787 dict_iterator_t it
, next
;
3789 struct handle_info
*hi
;
3791 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3792 next
= iter_next(it
);
3794 if ((hi
->opserv_level
> 0)
3796 || HANDLE_FLAGGED(hi
, FROZEN
)
3797 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3800 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3801 if ((now
- hi
->lastseen
) > expiry
) {
3802 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3803 nickserv_unregister_handle(hi
, NULL
, NULL
);
3807 if (nickserv_conf
.handle_expire_frequency
)
3808 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3812 nickserv_load_dict(const char *fname
)
3816 if (!(file
= fopen(fname
, "r"))) {
3817 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3820 while (!feof(file
)) {
3821 fgets(line
, sizeof(line
), file
);
3824 if (line
[strlen(line
)-1] == '\n')
3825 line
[strlen(line
)-1] = 0;
3826 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3829 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3832 static enum reclaim_action
3833 reclaim_action_from_string(const char *str
) {
3835 return RECLAIM_NONE
;
3836 else if (!irccasecmp(str
, "warn"))
3837 return RECLAIM_WARN
;
3838 else if (!irccasecmp(str
, "svsnick"))
3839 return RECLAIM_SVSNICK
;
3840 else if (!irccasecmp(str
, "kill"))
3841 return RECLAIM_KILL
;
3843 return RECLAIM_NONE
;
3847 nickserv_conf_read(void)
3849 dict_t conf_node
, child
;
3853 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3854 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3857 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3859 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3860 if (nickserv_conf
.valid_handle_regex_set
)
3861 regfree(&nickserv_conf
.valid_handle_regex
);
3863 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3864 nickserv_conf
.valid_handle_regex_set
= !err
;
3865 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3867 nickserv_conf
.valid_handle_regex_set
= 0;
3869 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3870 if (nickserv_conf
.valid_nick_regex_set
)
3871 regfree(&nickserv_conf
.valid_nick_regex
);
3873 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3874 nickserv_conf
.valid_nick_regex_set
= !err
;
3875 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3877 nickserv_conf
.valid_nick_regex_set
= 0;
3879 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3881 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3882 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3883 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3884 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3885 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3886 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3887 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3888 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3889 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3890 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3891 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3892 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3893 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3894 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3895 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3896 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3897 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3898 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3899 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3900 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3901 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3902 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3903 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3904 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3905 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3907 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3908 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3909 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3911 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3912 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3913 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3915 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3916 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3917 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3918 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3919 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3920 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3921 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3922 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3923 if (!nickserv_conf
.disable_nicks
) {
3924 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3925 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3926 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3927 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3928 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3929 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3930 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3931 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3933 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3934 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3935 const char *key
= iter_key(it
), *value
;
3939 if (!strncasecmp(key
, "uc_", 3))
3940 flag
= toupper(key
[3]);
3941 else if (!strncasecmp(key
, "lc_", 3))
3942 flag
= tolower(key
[3]);
3946 if ((pos
= handle_inverse_flags
[flag
])) {
3947 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3948 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3951 if (nickserv_conf
.weak_password_dict
)
3952 dict_delete(nickserv_conf
.weak_password_dict
);
3953 nickserv_conf
.weak_password_dict
= dict_new();
3954 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3955 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3956 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3957 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3959 nickserv_load_dict(str
);
3960 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3961 if (nickserv
&& str
)
3962 NickChange(nickserv
, str
, 0);
3963 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3964 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3965 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3966 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3967 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3968 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3969 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3970 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3971 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3972 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3973 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3974 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3975 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3976 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3977 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3978 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3979 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3980 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3981 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3982 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3984 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
3985 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3987 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
3988 nickserv_conf
.auto_oper
= str
? str
: "";
3990 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
3991 nickserv_conf
.auto_admin
= str
? str
: "";
3993 str
= conf_get_data("server/network", RECDB_QSTRING
);
3994 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3995 if (!nickserv_conf
.auth_policer_params
) {
3996 nickserv_conf
.auth_policer_params
= policer_params_new();
3997 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3998 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4000 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4001 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4002 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4006 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4008 char newnick
[NICKLEN
+1];
4017 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4019 case RECLAIM_SVSNICK
:
4021 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4022 } while (GetUserH(newnick
));
4023 irc_svsnick(nickserv
, user
, newnick
);
4026 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4027 irc_kill(nickserv
, user
, msg
);
4033 nickserv_reclaim_p(void *data
) {
4034 struct userNode
*user
= data
;
4035 struct nick_info
*ni
= get_nick_info(user
->nick
);
4037 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4041 check_user_nick(struct userNode
*user
) {
4042 struct nick_info
*ni
;
4043 user
->modes
&= ~FLAGS_REGNICK
;
4044 if (!(ni
= get_nick_info(user
->nick
)))
4046 if (user
->handle_info
== ni
->owner
) {
4047 user
->modes
|= FLAGS_REGNICK
;
4051 if (nickserv_conf
.warn_nick_owned
)
4052 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4053 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4055 if (nickserv_conf
.auto_reclaim_delay
)
4056 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4058 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4063 handle_new_user(struct userNode
*user
)
4065 return check_user_nick(user
);
4069 handle_account(struct userNode
*user
, const char *stamp
)
4071 struct handle_info
*hi
;
4074 #ifdef WITH_PROTOCOL_P10
4075 time_t timestamp
= 0;
4077 colon
= strchr(stamp
, ':');
4078 if(colon
&& colon
[1])
4081 timestamp
= atoi(colon
+1);
4083 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4084 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4086 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
);
4090 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4091 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4095 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4098 set_user_handle_info(user
, hi
, 0);
4100 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4105 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4107 struct handle_info
*hi
;
4109 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4110 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4111 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4113 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4114 check_user_nick(user
);
4118 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4120 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4121 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4122 set_user_handle_info(user
, NULL
, 0);
4125 static struct modcmd
*
4126 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4128 if (min_level
> 0) {
4130 sprintf(buf
, "%u", min_level
);
4131 if (must_be_qualified
) {
4132 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4134 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4136 } else if (min_level
== 0) {
4137 if (must_be_qualified
) {
4138 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4140 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4143 if (must_be_qualified
) {
4144 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4146 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4152 nickserv_db_cleanup(void)
4154 unreg_del_user_func(nickserv_remove_user
);
4155 userList_clean(&curr_helpers
);
4156 policer_params_delete(nickserv_conf
.auth_policer_params
);
4157 dict_delete(nickserv_handle_dict
);
4158 dict_delete(nickserv_nick_dict
);
4159 dict_delete(nickserv_opt_dict
);
4160 dict_delete(nickserv_allow_auth_dict
);
4161 dict_delete(nickserv_email_dict
);
4162 dict_delete(nickserv_id_dict
);
4163 dict_delete(nickserv_conf
.weak_password_dict
);
4164 free(auth_func_list
);
4165 free(unreg_func_list
);
4167 free(allowauth_func_list
);
4168 free(handle_merge_func_list
);
4169 free(failpw_func_list
);
4170 if (nickserv_conf
.valid_handle_regex_set
)
4171 regfree(&nickserv_conf
.valid_handle_regex
);
4172 if (nickserv_conf
.valid_nick_regex_set
)
4173 regfree(&nickserv_conf
.valid_nick_regex
);
4177 init_nickserv(const char *nick
)
4180 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4181 reg_new_user_func(handle_new_user
);
4182 reg_nick_change_func(handle_nick_change
);
4183 reg_del_user_func(nickserv_remove_user
);
4184 reg_account_func(handle_account
);
4186 /* set up handle_inverse_flags */
4187 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4188 for (i
=0; handle_flags
[i
]; i
++) {
4189 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4190 flag_access_levels
[i
] = 0;
4193 conf_register_reload(nickserv_conf_read
);
4194 nickserv_opt_dict
= dict_new();
4195 nickserv_email_dict
= dict_new();
4196 dict_set_free_keys(nickserv_email_dict
, free
);
4197 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4199 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4200 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4201 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4202 * a big pain to disable since its nolonger in the config file. ) -Rubin
4204 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4205 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4206 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4207 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4208 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4209 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4210 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4211 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4212 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4213 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4214 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4215 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4216 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4217 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4218 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4219 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4220 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4221 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4222 if (!nickserv_conf
.disable_nicks
) {
4223 /* nick management commands */
4224 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4225 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4226 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4227 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4228 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4229 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4231 if (nickserv_conf
.email_enabled
) {
4232 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4233 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4234 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4235 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4236 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4237 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4239 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4240 /* miscellaneous commands */
4241 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4242 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4243 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4244 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4245 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4247 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4248 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4249 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4250 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4251 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4252 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4253 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4254 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4255 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4256 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4257 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4258 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4259 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4260 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4261 if (nickserv_conf
.titlehost_suffix
) {
4262 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4263 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4265 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4266 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4267 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4269 nickserv_handle_dict
= dict_new();
4270 dict_set_free_keys(nickserv_handle_dict
, free
);
4271 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4273 nickserv_id_dict
= dict_new();
4274 dict_set_free_keys(nickserv_id_dict
, free
);
4276 nickserv_nick_dict
= dict_new();
4277 dict_set_free_data(nickserv_nick_dict
, free
);
4279 nickserv_allow_auth_dict
= dict_new();
4281 userList_init(&curr_helpers
);
4284 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4285 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4286 nickserv_service
= service_register(nickserv
);
4288 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4289 reg_exit_func(nickserv_db_cleanup
);
4290 if(nickserv_conf
.handle_expire_frequency
)
4291 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4292 message_register_table(msgtab
);