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"
77 #define KEY_PASSWD "passwd"
78 #define KEY_NICKS "nicks"
79 #define KEY_MASKS "masks"
80 #define KEY_OPSERV_LEVEL "opserv_level"
81 #define KEY_FLAGS "flags"
82 #define KEY_REGISTER_ON "register"
83 #define KEY_LAST_SEEN "lastseen"
84 #define KEY_INFO "info"
85 #define KEY_USERLIST_STYLE "user_style"
86 #define KEY_SCREEN_WIDTH "screen_width"
87 #define KEY_LAST_AUTHED_HOST "last_authed_host"
88 #define KEY_LAST_QUIT_HOST "last_quit_host"
89 #define KEY_EMAIL_ADDR "email_addr"
90 #define KEY_COOKIE "cookie"
91 #define KEY_COOKIE_DATA "data"
92 #define KEY_COOKIE_TYPE "type"
93 #define KEY_COOKIE_EXPIRES "expires"
94 #define KEY_ACTIVATION "activation"
95 #define KEY_PASSWORD_CHANGE "password change"
96 #define KEY_EMAIL_CHANGE "email change"
97 #define KEY_ALLOWAUTH "allowauth"
98 #define KEY_EPITHET "epithet"
99 #define KEY_TABLE_WIDTH "table_width"
100 #define KEY_ANNOUNCEMENTS "announcements"
101 #define KEY_MAXLOGINS "maxlogins"
102 #define KEY_FAKEHOST "fakehost"
104 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
106 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
107 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
108 typedef OPTION_FUNC(option_func_t
);
110 DEFINE_LIST(handle_info_list
, struct handle_info
*);
112 #define NICKSERV_MIN_PARMS(N) do { \
114 reply("MSG_MISSING_PARAMS", argv[0]); \
115 svccmd_send_help_brief(user, nickserv, cmd); \
119 struct userNode
*nickserv
;
120 struct userList curr_helpers
;
121 const char *handle_flags
= HANDLE_FLAGS
;
123 static struct module *nickserv_module
;
124 static struct service
*nickserv_service
;
125 static struct log_type
*NS_LOG
;
126 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
127 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
128 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
129 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
130 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
131 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
132 static char handle_inverse_flags
[256];
133 static unsigned int flag_access_levels
[32];
134 static const struct message_entry msgtab
[] = {
135 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
136 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
137 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
138 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
139 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
140 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
141 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
142 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
143 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
144 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
145 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
146 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
147 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
148 { "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." },
149 { "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." },
150 { "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." },
151 { "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." },
152 { "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." },
153 { "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." },
154 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
155 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
156 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
157 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
158 { "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." },
159 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
160 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
161 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
162 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
163 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
164 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
165 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
166 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
167 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
168 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
169 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
170 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
171 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
172 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
173 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
174 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
175 { "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)" },
176 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
177 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
178 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
179 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
180 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
181 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
182 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
183 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
184 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
185 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
186 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
187 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
188 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
189 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
190 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
191 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
192 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
193 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
194 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
195 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
196 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
197 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
198 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
199 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
200 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
201 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
202 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
203 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
204 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
205 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
206 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
207 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
208 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
209 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
210 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
211 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
212 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
213 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
214 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
215 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
216 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
217 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
218 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
219 { "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)." },
220 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
221 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
222 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
223 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
224 { "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." },
225 { "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." },
226 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
227 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
228 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
229 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
230 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
231 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
232 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
233 { "NSMSG_PASS_SUCCESS", "Password changed." },
234 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
235 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
236 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
237 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
238 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
239 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
240 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
241 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
242 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
243 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
244 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
245 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
246 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
247 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
248 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
249 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
250 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
251 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
252 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
253 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
254 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
255 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
256 { "NSMSG_NO_ACCESS", "Access denied." },
257 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
258 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
259 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
260 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
261 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
262 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
263 { "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." },
264 { "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." },
265 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
266 { "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." },
267 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
268 { "NSMSG_SEARCH_MATCH", "Match: %s" },
269 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
270 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
271 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
272 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
273 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
274 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
275 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
276 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
277 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
278 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
279 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
280 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
281 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
282 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
283 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
284 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
285 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
286 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
287 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
288 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
289 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
290 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
291 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
292 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
293 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
294 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
295 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
296 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
297 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
298 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
299 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
300 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
302 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
303 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
305 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
306 { "NSEMAIL_ACTIVATION_BODY",
307 "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"
309 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
310 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
311 "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"
312 "/msg %3$s@%4$s AUTH %5$s your-password\n"
313 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
314 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
316 "If you did NOT request this account, you do not need to do anything.\n"
317 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
318 { "NSEMAIL_ACTIVATION_BODY_WEB",
319 "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"
321 "To verify your email address and complete the account registration, visit the following URL:\n"
322 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
324 "If you did NOT request this account, you do not need to do anything.\n"
325 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
326 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
327 { "NSEMAIL_PASSWORD_CHANGE_BODY",
328 "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"
329 "To complete the password change, log on to %1$s and type the following command:\n"
330 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
331 "If you did NOT request your password to be changed, you do not need to do anything.\n"
332 "Please contact the %1$s staff if you have questions." },
333 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
334 "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"
335 "To complete the password change, click the following URL:\n"
336 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
337 "If you did NOT request your password to be changed, you do not need to do anything.\n"
338 "Please contact the %1$s staff if you have questions." },
339 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
340 #ifdef stupid_verify_old_email
341 { "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." },
342 { "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." },
344 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
345 { "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." },
346 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
347 { "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." },
348 { "CHECKPASS_YES", "Yes." },
349 { "CHECKPASS_NO", "No." },
353 enum reclaim_action
{
359 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
360 static void nickserv_reclaim_p(void *data
);
363 unsigned int disable_nicks
: 1;
364 unsigned int valid_handle_regex_set
: 1;
365 unsigned int valid_nick_regex_set
: 1;
366 unsigned int autogag_enabled
: 1;
367 unsigned int email_enabled
: 1;
368 unsigned int email_required
: 1;
369 unsigned int default_hostmask
: 1;
370 unsigned int warn_nick_owned
: 1;
371 unsigned int warn_clone_auth
: 1;
372 unsigned int sync_log
: 1;
373 unsigned long nicks_per_handle
;
374 unsigned long password_min_length
;
375 unsigned long password_min_digits
;
376 unsigned long password_min_upper
;
377 unsigned long password_min_lower
;
378 unsigned long db_backup_frequency
;
379 unsigned long handle_expire_frequency
;
380 unsigned long autogag_duration
;
381 unsigned long email_visible_level
;
382 unsigned long cookie_timeout
;
383 unsigned long handle_expire_delay
;
384 unsigned long nochan_handle_expire_delay
;
385 unsigned long modoper_level
;
386 unsigned long set_epithet_level
;
387 unsigned long set_title_level
;
388 unsigned long set_fakehost_level
;
389 unsigned long handles_per_email
;
390 unsigned long email_search_level
;
391 const char *network_name
;
392 const char *titlehost_suffix
;
393 regex_t valid_handle_regex
;
394 regex_t valid_nick_regex
;
395 dict_t weak_password_dict
;
396 struct policer_params
*auth_policer_params
;
397 enum reclaim_action reclaim_action
;
398 enum reclaim_action auto_reclaim_action
;
399 unsigned long auto_reclaim_delay
;
400 unsigned char default_maxlogins
;
401 unsigned char hard_maxlogins
;
402 const char *auto_oper
;
403 const char *auto_admin
;
406 /* We have 2^32 unique account IDs to use. */
407 unsigned long int highest_id
= 0;
410 canonicalize_hostmask(char *mask
)
412 char *out
= mask
, *temp
;
413 if ((temp
= strchr(mask
, '!'))) {
415 while (*temp
) *out
++ = *temp
++;
421 static struct handle_info
*
422 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
424 struct handle_info
*hi
;
426 #ifdef WITH_PROTOCOL_BAHAMUT
427 char id_base64
[IDLEN
+ 1];
430 /* Assign a unique account ID to the account; note that 0 is
431 an invalid account ID. 1 is therefore the first account ID. */
433 id
= 1 + highest_id
++;
435 /* Note: highest_id is and must always be the highest ID. */
436 if(id
> highest_id
) {
440 inttobase64(id_base64
, id
, IDLEN
);
442 /* Make sure an account with the same ID doesn't exist. If a
443 duplicate is found, log some details and assign a new one.
444 This should be impossible, but it never hurts to expect it. */
445 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
446 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
452 hi
= calloc(1, sizeof(*hi
));
453 hi
->userlist_style
= HI_DEFAULT_STYLE
;
454 hi
->announcements
= '?';
455 hi
->handle
= strdup(handle
);
456 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
458 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
460 #ifdef WITH_PROTOCOL_BAHAMUT
462 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
469 register_nick(const char *nick
, struct handle_info
*owner
)
471 struct nick_info
*ni
;
472 ni
= malloc(sizeof(struct nick_info
));
473 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
475 ni
->next
= owner
->nicks
;
477 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
481 delete_nick(struct nick_info
*ni
)
483 struct nick_info
*last
, *next
;
484 struct userNode
*user
;
485 /* Check to see if we should mark a user as unregistered. */
486 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
487 user
->modes
&= ~FLAGS_REGNICK
;
490 /* Remove ni from the nick_info linked list. */
491 if (ni
== ni
->owner
->nicks
) {
492 ni
->owner
->nicks
= ni
->next
;
494 last
= ni
->owner
->nicks
;
500 last
->next
= next
->next
;
502 dict_remove(nickserv_nick_dict
, ni
->nick
);
505 static unreg_func_t
*unreg_func_list
;
506 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
509 reg_unreg_func(unreg_func_t func
)
511 if (unreg_func_used
== unreg_func_size
) {
512 if (unreg_func_size
) {
513 unreg_func_size
<<= 1;
514 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
517 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
520 unreg_func_list
[unreg_func_used
++] = func
;
524 nickserv_free_cookie(void *data
)
526 struct handle_cookie
*cookie
= data
;
527 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
528 if (cookie
->data
) free(cookie
->data
);
533 free_handle_info(void *vhi
)
535 struct handle_info
*hi
= vhi
;
537 #ifdef WITH_PROTOCOL_BAHAMUT
540 inttobase64(id
, hi
->id
, IDLEN
);
541 dict_remove(nickserv_id_dict
, id
);
544 free_string_list(hi
->masks
);
548 delete_nick(hi
->nicks
);
553 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
554 nickserv_free_cookie(hi
->cookie
);
556 if (hi
->email_addr
) {
557 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
558 handle_info_list_remove(hil
, hi
);
560 dict_remove(nickserv_email_dict
, hi
->email_addr
);
565 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
568 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
571 struct userNode
*uNode
;
573 for (n
=0; n
<unreg_func_used
; n
++)
574 unreg_func_list
[n
](notify
, hi
);
576 if (nickserv_conf
.sync_log
) {
577 uNode
= GetUserH(hi
->users
->nick
);
581 set_user_handle_info(hi
->users
, NULL
, 0);
584 if (nickserv_conf
.disable_nicks
)
585 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
587 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
590 if (nickserv_conf
.sync_log
)
591 SyncLog("UNREGISTER %s", hi
->handle
);
593 dict_remove(nickserv_handle_dict
, hi
->handle
);
597 get_handle_info(const char *handle
)
599 return dict_find(nickserv_handle_dict
, handle
, 0);
603 get_nick_info(const char *nick
)
605 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
609 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
614 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
615 mn
= channel
->members
.list
[nn
];
616 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
623 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
624 if (!user
->handle_info
) {
626 send_message(user
, bot
, "MSG_AUTHENTICATE");
630 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
632 send_message(user
, bot
, "NSMSG_NO_ACCESS");
636 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
638 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
642 if (user
->handle_info
->opserv_level
< min_level
) {
644 send_message(user
, bot
, "NSMSG_NO_ACCESS");
652 is_valid_handle(const char *handle
)
654 struct userNode
*user
;
655 /* cant register a juped nick/service nick as handle, to prevent confusion */
656 user
= GetUserH(handle
);
657 if (user
&& IsLocal(user
))
659 /* check against maximum length */
660 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
662 /* for consistency, only allow account names that could be nicks */
663 if (!is_valid_nick(handle
))
665 /* disallow account names that look like bad words */
666 if (opserv_bad_channel(handle
))
668 /* test either regex or containing all valid chars */
669 if (nickserv_conf
.valid_handle_regex_set
) {
670 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
673 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
674 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
678 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
683 is_registerable_nick(const char *nick
)
685 /* make sure it could be used as an account name */
686 if (!is_valid_handle(nick
))
689 if (strlen(nick
) > NICKLEN
)
691 /* test either regex or as valid handle */
692 if (nickserv_conf
.valid_nick_regex_set
) {
693 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
696 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
697 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
705 is_valid_email_addr(const char *email
)
707 return strchr(email
, '@') != NULL
;
711 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
713 if (hi
->email_addr
) {
714 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
715 return hi
->email_addr
;
725 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
727 struct handle_info
*hi
;
728 struct userNode
*target
;
732 if (!(hi
= get_handle_info(++name
))) {
733 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
738 if (!(target
= GetUserH(name
))) {
739 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
742 if (IsLocal(target
)) {
743 if (IsService(target
))
744 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
746 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
749 if (!(hi
= target
->handle_info
)) {
750 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
758 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
759 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
761 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
762 if ((user
->handle_info
->opserv_level
== 1000)
763 || (user
->handle_info
== hi
)
764 || ((user
->handle_info
->opserv_level
== 0)
765 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
766 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
770 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
774 static struct handle_info
*
775 get_victim_oper(struct userNode
*user
, const char *target
)
777 struct handle_info
*hi
;
778 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
780 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
781 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
784 return oper_outranks(user
, hi
) ? hi
: NULL
;
788 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
792 /* If no hostmasks on the account, allow it. */
793 if (!hi
->masks
->used
)
795 /* If any hostmask matches, allow it. */
796 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
797 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
799 /* If they are allowauthed to this account, allow it (removing the aa). */
800 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
801 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
804 /* The user is not allowed to use this account. */
809 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
812 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
816 if (len
< nickserv_conf
.password_min_length
) {
818 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
821 if (!irccasecmp(pass
, handle
)) {
823 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
826 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
829 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
832 for (i
=0; i
<len
; i
++) {
833 if (isdigit(pass
[i
]))
835 if (isupper(pass
[i
]))
837 if (islower(pass
[i
]))
840 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
841 || (cnt_upper
< nickserv_conf
.password_min_upper
)
842 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
844 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
850 static auth_func_t
*auth_func_list
;
851 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
854 reg_auth_func(auth_func_t func
)
856 if (auth_func_used
== auth_func_size
) {
857 if (auth_func_size
) {
858 auth_func_size
<<= 1;
859 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
862 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
865 auth_func_list
[auth_func_used
++] = func
;
868 static handle_rename_func_t
*rf_list
;
869 static unsigned int rf_list_size
, rf_list_used
;
872 reg_handle_rename_func(handle_rename_func_t func
)
874 if (rf_list_used
== rf_list_size
) {
877 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
880 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
883 rf_list
[rf_list_used
++] = func
;
887 generate_fakehost(struct handle_info
*handle
)
889 extern const char *hidden_host_suffix
;
890 static char buffer
[HOSTLEN
+1];
892 if (!handle
->fakehost
) {
893 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
895 } else if (handle
->fakehost
[0] == '.') {
896 /* A leading dot indicates the stored value is actually a title. */
897 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
900 return handle
->fakehost
;
904 apply_fakehost(struct handle_info
*handle
)
906 struct userNode
*target
;
911 fake
= generate_fakehost(handle
);
912 for (target
= handle
->users
; target
; target
= target
->next_authed
)
913 assign_fakehost(target
, fake
, 1);
916 void send_func_list(struct userNode
*user
)
919 struct handle_info
*old_info
;
921 old_info
= user
->handle_info
;
923 for (n
=0; n
<auth_func_used
; n
++)
924 auth_func_list
[n
](user
, old_info
);
928 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
931 struct handle_info
*old_info
;
933 /* This can happen if somebody uses COOKIE while authed, or if
934 * they re-auth to their current handle (which is silly, but users
936 if (user
->handle_info
== hi
)
939 if (user
->handle_info
) {
940 struct userNode
*other
;
943 userList_remove(&curr_helpers
, user
);
945 /* remove from next_authed linked list */
946 if (user
->handle_info
->users
== user
) {
947 user
->handle_info
->users
= user
->next_authed
;
949 for (other
= user
->handle_info
->users
;
950 other
->next_authed
!= user
;
951 other
= other
->next_authed
) ;
952 other
->next_authed
= user
->next_authed
;
954 /* if nobody left on old handle, and they're not an oper, remove !god */
955 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
956 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
957 /* record them as being last seen at this time */
958 user
->handle_info
->lastseen
= now
;
959 /* and record their hostmask */
960 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
962 old_info
= user
->handle_info
;
963 user
->handle_info
= hi
;
964 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
965 HANDLE_CLEAR_FLAG(hi
, HELPING
);
967 if (GetUserH(user
->nick
)) {
968 for (n
=0; n
<auth_func_used
; n
++)
969 auth_func_list
[n
](user
, old_info
);
974 struct nick_info
*ni
;
976 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
977 if (nickserv_conf
.warn_clone_auth
) {
978 struct userNode
*other
;
979 for (other
= hi
->users
; other
; other
= other
->next_authed
)
980 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
983 user
->next_authed
= hi
->users
;
987 userList_append(&curr_helpers
, user
);
989 if (hi
->fakehost
|| old_info
)
993 #ifdef WITH_PROTOCOL_BAHAMUT
994 /* Stamp users with their account ID. */
996 inttobase64(id
, hi
->id
, IDLEN
);
997 #elif WITH_PROTOCOL_P10
998 /* Stamp users with their account name. */
999 char *id
= hi
->handle
;
1001 const char *id
= "???";
1003 if (!nickserv_conf
.disable_nicks
) {
1004 struct nick_info
*ni
;
1005 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1006 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1007 user
->modes
|= FLAGS_REGNICK
;
1012 StampUser(user
, id
, hi
->registered
);
1015 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1016 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1018 /* We cannot clear the user's account ID, unfortunately. */
1019 user
->next_authed
= NULL
;
1023 static struct handle_info
*
1024 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1026 struct handle_info
*hi
;
1027 struct nick_info
*ni
;
1028 char crypted
[MD5_CRYPT_LENGTH
];
1030 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1031 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1035 if(strlen(handle
) > 15)
1037 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1041 if (!is_secure_password(handle
, passwd
, user
))
1044 cryptpass(passwd
, crypted
);
1045 hi
= register_handle(handle
, crypted
, 0);
1046 hi
->masks
= alloc_string_list(1);
1048 hi
->language
= lang_C
;
1049 hi
->registered
= now
;
1051 hi
->flags
= HI_DEFAULT_FLAGS
;
1052 if (settee
&& !no_auth
)
1053 set_user_handle_info(settee
, hi
, 1);
1056 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1057 else if (nickserv_conf
.disable_nicks
)
1058 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1059 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1060 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1062 register_nick(user
->nick
, hi
);
1063 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1065 if (settee
&& (user
!= settee
))
1066 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1071 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1073 cookie
->hi
->cookie
= cookie
;
1074 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1077 /* Contributed by the great sneep of afternet ;) */
1078 /* Since this gets used in a URL, we want to avoid stuff that confuses
1079 * email clients such as ] and ?. a-z, 0-9 only.
1081 void genpass(char *str
, int len
)
1086 for(i
= 0; i
< len
; i
++)
1090 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1091 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1099 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1101 struct handle_cookie
*cookie
;
1102 char subject
[128], body
[4096], *misc
;
1103 const char *netname
, *fmt
;
1107 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1111 cookie
= calloc(1, sizeof(*cookie
));
1113 cookie
->type
= type
;
1114 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1116 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1117 /* Adding dedicated password gen function for more control -Rubin */
1118 genpass(cookie
->cookie
, 10);
1120 *inttobase64(cookie->cookie, rand(), 5);
1121 *inttobase64(cookie->cookie+5, rand(), 5);
1124 netname
= nickserv_conf
.network_name
;
1127 switch (cookie
->type
) {
1129 hi
->passwd
[0] = 0; /* invalidate password */
1130 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1131 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1132 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1135 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1137 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1139 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1142 case PASSWORD_CHANGE
:
1143 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1144 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1145 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1147 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1149 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1150 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1153 misc
= hi
->email_addr
;
1154 hi
->email_addr
= cookie
->data
;
1155 #ifdef stupid_verify_old_email
1157 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1158 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1159 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1160 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1161 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1162 sendmail(nickserv
, hi
, subject
, body
, 1);
1163 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1164 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1167 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1168 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1169 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1170 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1171 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1172 sendmail(nickserv
, hi
, subject
, body
, 1);
1174 #ifdef stupid_verify_old_email
1177 hi
->email_addr
= misc
;
1180 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1181 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1182 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1183 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1184 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1187 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1191 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1192 nickserv_bake_cookie(cookie
);
1196 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1198 cookie
->hi
->cookie
= NULL
;
1199 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1200 nickserv_free_cookie(cookie
);
1204 nickserv_free_email_addr(void *data
)
1206 handle_info_list_clean(data
);
1211 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1213 struct handle_info_list
*hil
;
1214 /* Remove from old handle_info_list ... */
1215 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1216 handle_info_list_remove(hil
, hi
);
1217 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1218 hi
->email_addr
= NULL
;
1220 /* Add to the new list.. */
1221 if (new_email_addr
) {
1222 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1223 hil
= calloc(1, sizeof(*hil
));
1224 hil
->tag
= strdup(new_email_addr
);
1225 handle_info_list_init(hil
);
1226 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1228 handle_info_list_append(hil
, hi
);
1229 hi
->email_addr
= hil
->tag
;
1233 static NICKSERV_FUNC(cmd_register
)
1235 struct handle_info
*hi
;
1236 const char *email_addr
, *password
;
1237 char syncpass
[MD5_CRYPT_LENGTH
];
1238 int no_auth
, weblink
;
1240 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1241 /* Require the first handle registered to belong to someone +o. */
1242 reply("NSMSG_REQUIRE_OPER");
1246 if (user
->handle_info
) {
1247 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1251 if (IsRegistering(user
)) {
1252 reply("NSMSG_ALREADY_REGISTERING");
1256 if (IsStamped(user
)) {
1257 /* Unauthenticated users might still have been stamped
1258 previously and could therefore have a hidden host;
1259 do not allow them to register a new account. */
1260 reply("NSMSG_STAMPED_REGISTER");
1264 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1266 if (!is_valid_handle(argv
[1])) {
1267 reply("NSMSG_BAD_HANDLE", argv
[1]);
1272 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1273 struct handle_info_list
*hil
;
1276 /* Remember email address. */
1277 email_addr
= argv
[3];
1279 /* Check that the email address looks valid.. */
1280 if (!is_valid_email_addr(email_addr
)) {
1281 reply("NSMSG_BAD_EMAIL_ADDR");
1285 /* .. and that we are allowed to send to it. */
1286 if ((str
= sendmail_prohibited_address(email_addr
))) {
1287 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1291 /* If we do email verify, make sure we don't spam the address. */
1292 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1294 for (nn
=0; nn
<hil
->used
; nn
++) {
1295 if (hil
->list
[nn
]->cookie
) {
1296 reply("NSMSG_EMAIL_UNACTIVATED");
1300 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1301 reply("NSMSG_EMAIL_OVERUSED");
1314 /* Webregister hack - send URL instead of IRC cookie
1317 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1321 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1323 /* Add any masks they should get. */
1324 if (nickserv_conf
.default_hostmask
) {
1325 string_list_append(hi
->masks
, strdup("*@*"));
1327 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1328 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1329 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1332 /* If they're the first to register, give them level 1000. */
1333 if (dict_size(nickserv_handle_dict
) == 1) {
1334 hi
->opserv_level
= 1000;
1335 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1338 /* Set their email address. */
1340 nickserv_set_email_addr(hi
, email_addr
);
1342 /* If they need to do email verification, tell them. */
1344 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1346 /* Set registering flag.. */
1347 user
->modes
|= FLAGS_REGISTERING
;
1349 if (nickserv_conf
.sync_log
) {
1350 cryptpass(password
, syncpass
);
1352 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1353 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1356 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1359 /* this wont work if email is required .. */
1360 process_adduser_pending(user
);
1365 static NICKSERV_FUNC(cmd_oregister
)
1368 struct userNode
*settee
;
1369 struct handle_info
*hi
;
1371 NICKSERV_MIN_PARMS(nickserv_conf
.email_required
? 5 : 4);
1373 if (!is_valid_handle(argv
[1])) {
1374 reply("NSMSG_BAD_HANDLE", argv
[1]);
1378 if (nickserv_conf
.email_required
) {
1379 if (!is_valid_email_addr(argv
[4])) {
1380 reply("NSMSG_BAD_EMAIL_ADDR");
1385 if (strchr(argv
[3], '@')) {
1386 mask
= canonicalize_hostmask(strdup(argv
[3]));
1388 settee
= GetUserH(nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1390 reply("MSG_NICK_UNKNOWN", nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1397 } else if ((settee
= GetUserH(argv
[3]))) {
1398 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1400 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1403 if (settee
&& settee
->handle_info
) {
1404 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1408 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1409 if (nickserv_conf
.email_required
) {
1410 nickserv_set_email_addr(hi
, argv
[4]);
1411 if (nickserv_conf
.sync_log
)
1412 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, argv
[4], user
->info
);
1417 string_list_append(hi
->masks
, mask
);
1421 static NICKSERV_FUNC(cmd_handleinfo
)
1424 unsigned int i
, pos
=0, herelen
;
1425 struct userNode
*target
, *next_un
;
1426 struct handle_info
*hi
;
1427 const char *nsmsg_none
;
1430 if (!(hi
= user
->handle_info
)) {
1431 reply("NSMSG_MUST_AUTH");
1434 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1438 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1439 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1441 #ifdef WITH_PROTOCOL_BAHAMUT
1442 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1444 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1447 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1448 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1450 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1453 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1454 if (HANDLE_FLAGGED(hi
, FROZEN
))
1455 reply("NSMSG_HANDLEINFO_VACATION");
1457 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1458 struct do_not_register
*dnr
;
1459 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1460 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1461 if (!oper_outranks(user
, hi
))
1463 } else if (hi
!= user
->handle_info
) {
1464 reply("NSMSG_HANDLEINFO_END");
1468 if (nickserv_conf
.email_enabled
)
1469 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1473 switch (hi
->cookie
->type
) {
1474 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1475 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1476 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1477 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1478 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1484 unsigned long flen
= 1;
1485 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1487 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1488 if (hi
->flags
& 1 << i
)
1489 flags
[flen
++] = handle_flags
[i
];
1491 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1493 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1496 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1497 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1498 || (hi
->opserv_level
> 0)) {
1499 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1503 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1505 if (hi
->last_quit_host
[0])
1506 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1508 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1510 if (nickserv_conf
.disable_nicks
) {
1511 /* nicks disabled; don't show anything about registered nicks */
1512 } else if (hi
->nicks
) {
1513 struct nick_info
*ni
, *next_ni
;
1514 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1515 herelen
= strlen(ni
->nick
);
1516 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1518 goto print_nicks_buff
;
1522 memcpy(buff
+pos
, ni
->nick
, herelen
);
1523 pos
+= herelen
; buff
[pos
++] = ' ';
1527 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1532 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1535 if (hi
->masks
->used
) {
1536 for (i
=0; i
< hi
->masks
->used
; i
++) {
1537 herelen
= strlen(hi
->masks
->list
[i
]);
1538 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1540 goto print_mask_buff
;
1542 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1543 pos
+= herelen
; buff
[pos
++] = ' ';
1544 if (i
+1 == hi
->masks
->used
) {
1547 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1552 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1556 struct userData
*channel
, *next
;
1559 for (channel
= hi
->channels
; channel
; channel
= next
) {
1560 next
= channel
->u_next
;
1561 name
= channel
->channel
->channel
->name
;
1562 herelen
= strlen(name
);
1563 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1565 goto print_chans_buff
;
1567 if (IsUserSuspended(channel
))
1569 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1573 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1578 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1581 for (target
= hi
->users
; target
; target
= next_un
) {
1582 herelen
= strlen(target
->nick
);
1583 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1585 goto print_cnick_buff
;
1587 next_un
= target
->next_authed
;
1589 memcpy(buff
+pos
, target
->nick
, herelen
);
1590 pos
+= herelen
; buff
[pos
++] = ' ';
1594 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1599 reply("NSMSG_HANDLEINFO_END");
1603 static NICKSERV_FUNC(cmd_userinfo
)
1605 struct userNode
*target
;
1607 NICKSERV_MIN_PARMS(2);
1608 if (!(target
= GetUserH(argv
[1]))) {
1609 reply("MSG_NICK_UNKNOWN", argv
[1]);
1612 if (target
->handle_info
)
1613 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1615 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1619 static NICKSERV_FUNC(cmd_nickinfo
)
1621 struct nick_info
*ni
;
1623 NICKSERV_MIN_PARMS(2);
1624 if (!(ni
= get_nick_info(argv
[1]))) {
1625 reply("MSG_NICK_UNKNOWN", argv
[1]);
1628 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1632 static NICKSERV_FUNC(cmd_rename_handle
)
1634 struct handle_info
*hi
;
1635 struct userNode
*uNode
;
1636 char msgbuf
[MAXLEN
], *old_handle
;
1639 NICKSERV_MIN_PARMS(3);
1640 if (!(hi
= get_victim_oper(user
, argv
[1])))
1642 if (!is_valid_handle(argv
[2])) {
1643 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1646 if (get_handle_info(argv
[2])) {
1647 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1650 if(strlen(argv
[2]) > 15)
1652 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1656 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1657 hi
->handle
= strdup(argv
[2]);
1658 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1659 for (nn
=0; nn
<rf_list_used
; nn
++)
1660 rf_list
[nn
](hi
, old_handle
);
1661 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1664 if (nickserv_conf
.sync_log
) {
1665 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1666 irc_rename(uNode
, hi
->handle
);
1668 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1671 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1672 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1677 static failpw_func_t
*failpw_func_list
;
1678 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1681 reg_failpw_func(failpw_func_t func
)
1683 if (failpw_func_used
== failpw_func_size
) {
1684 if (failpw_func_size
) {
1685 failpw_func_size
<<= 1;
1686 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1688 failpw_func_size
= 8;
1689 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1692 failpw_func_list
[failpw_func_used
++] = func
;
1696 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1698 * called by nefariouses enhanced AC login-on-connect code
1701 struct handle_info
*loc_auth(char *handle
, char *password
)
1703 int pw_arg
, used
, maxlogins
;
1706 struct handle_info
*hi
;
1707 struct userNode
*other
;
1709 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1715 /* We don't know the users hostname, or anything because they
1716 * havn't registered yet. So we can only allow LOC if your
1717 * account has *@* as a hostmask.
1719 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1721 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1730 /* Responses from here on look up the language used by the handle they asked about. */
1731 if (!checkpass(password
, hi
->passwd
)) {
1734 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1737 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1738 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1739 if (++used
>= maxlogins
) {
1746 static NICKSERV_FUNC(cmd_auth
)
1748 int pw_arg
, used
, maxlogins
;
1749 struct handle_info
*hi
;
1751 struct userNode
*other
;
1753 if (user
->handle_info
) {
1754 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1757 if (IsStamped(user
)) {
1758 /* Unauthenticated users might still have been stamped
1759 previously and could therefore have a hidden host;
1760 do not allow them to authenticate. */
1761 reply("NSMSG_STAMPED_AUTH");
1765 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1767 } else if (argc
== 2) {
1768 if (nickserv_conf
.disable_nicks
) {
1769 if (!(hi
= get_handle_info(user
->nick
))) {
1770 reply("NSMSG_HANDLE_NOT_FOUND");
1774 /* try to look up their handle from their nick */
1775 struct nick_info
*ni
;
1776 ni
= get_nick_info(user
->nick
);
1778 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1785 reply("MSG_MISSING_PARAMS", argv
[0]);
1786 svccmd_send_help_brief(user
, nickserv
, cmd
);
1790 reply("NSMSG_HANDLE_NOT_FOUND");
1793 /* Responses from here on look up the language used by the handle they asked about. */
1794 passwd
= argv
[pw_arg
];
1795 if (!valid_user_for(user
, hi
)) {
1796 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1797 send_message_type(4, user
, cmd
->parent
->bot
,
1798 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1801 send_message_type(4, user
, cmd
->parent
->bot
,
1802 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1804 argv
[pw_arg
] = "BADMASK";
1807 if (!checkpass(passwd
, hi
->passwd
)) {
1809 send_message_type(4, user
, cmd
->parent
->bot
,
1810 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1811 argv
[pw_arg
] = "BADPASS";
1812 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1813 if (nickserv_conf
.autogag_enabled
) {
1814 if (!user
->auth_policer
.params
) {
1815 user
->auth_policer
.last_req
= now
;
1816 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1818 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1820 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1821 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1822 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1824 argv
[pw_arg
] = "GAGGED";
1829 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1830 send_message_type(4, user
, cmd
->parent
->bot
,
1831 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1832 argv
[pw_arg
] = "SUSPENDED";
1835 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1836 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1837 if (++used
>= maxlogins
) {
1838 send_message_type(4, user
, cmd
->parent
->bot
,
1839 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1841 argv
[pw_arg
] = "MAXLOGINS";
1846 set_user_handle_info(user
, hi
, 1);
1847 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1848 reply("NSMSG_PLEASE_SET_EMAIL");
1849 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1850 reply("NSMSG_WEAK_PASSWORD");
1851 if (hi
->passwd
[0] != '$')
1852 cryptpass(passwd
, hi
->passwd
);
1854 /* If a channel was waiting for this user to auth,
1855 * finish adding them */
1856 process_adduser_pending(user
);
1858 reply("NSMSG_AUTH_SUCCESS");
1861 /* Set +x if autohide is on */
1862 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
1863 irc_umode(user
, "+x");
1865 if(!IsOper(user
)) /* If they arnt already opered.. */
1867 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
1868 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
1870 irc_umode(user
,nickserv_conf
.auto_admin
);
1871 reply("NSMSG_AUTO_OPER_ADMIN");
1873 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
1875 irc_umode(user
,nickserv_conf
.auto_oper
);
1876 reply("NSMSG_AUTO_OPER");
1880 /* Wipe out the pass for the logs */
1881 argv
[pw_arg
] = "****";
1885 static allowauth_func_t
*allowauth_func_list
;
1886 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1889 reg_allowauth_func(allowauth_func_t func
)
1891 if (allowauth_func_used
== allowauth_func_size
) {
1892 if (allowauth_func_size
) {
1893 allowauth_func_size
<<= 1;
1894 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1896 allowauth_func_size
= 8;
1897 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1900 allowauth_func_list
[allowauth_func_used
++] = func
;
1903 static NICKSERV_FUNC(cmd_allowauth
)
1905 struct userNode
*target
;
1906 struct handle_info
*hi
;
1909 NICKSERV_MIN_PARMS(2);
1910 if (!(target
= GetUserH(argv
[1]))) {
1911 reply("MSG_NICK_UNKNOWN", argv
[1]);
1914 if (target
->handle_info
) {
1915 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1918 if (IsStamped(target
)) {
1919 /* Unauthenticated users might still have been stamped
1920 previously and could therefore have a hidden host;
1921 do not allow them to authenticate to an account. */
1922 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1927 else if (!(hi
= get_handle_info(argv
[2]))) {
1928 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1932 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1933 reply("MSG_USER_OUTRANKED", hi
->handle
);
1936 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1937 || (hi
->opserv_level
> 0))
1938 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1939 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1942 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1943 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1944 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1945 if (nickserv_conf
.email_enabled
)
1946 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1948 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1949 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1951 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1953 for (n
=0; n
<allowauth_func_used
; n
++)
1954 allowauth_func_list
[n
](user
, target
, hi
);
1958 static NICKSERV_FUNC(cmd_authcookie
)
1960 struct handle_info
*hi
;
1962 NICKSERV_MIN_PARMS(2);
1963 if (user
->handle_info
) {
1964 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1967 if (IsStamped(user
)) {
1968 /* Unauthenticated users might still have been stamped
1969 previously and could therefore have a hidden host;
1970 do not allow them to authenticate to an account. */
1971 reply("NSMSG_STAMPED_AUTHCOOKIE");
1974 if (!(hi
= get_handle_info(argv
[1]))) {
1975 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1978 if (!hi
->email_addr
) {
1979 reply("MSG_SET_EMAIL_ADDR");
1982 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1986 static NICKSERV_FUNC(cmd_delcookie
)
1988 struct handle_info
*hi
;
1990 hi
= user
->handle_info
;
1992 reply("NSMSG_NO_COOKIE");
1995 switch (hi
->cookie
->type
) {
1998 reply("NSMSG_MUST_TIME_OUT");
2001 nickserv_eat_cookie(hi
->cookie
);
2002 reply("NSMSG_ATE_COOKIE");
2008 static NICKSERV_FUNC(cmd_odelcookie
)
2010 struct handle_info
*hi
;
2012 NICKSERV_MIN_PARMS(2);
2014 if (!(hi
= get_victim_oper(user
, argv
[1])))
2018 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2022 nickserv_eat_cookie(hi
->cookie
);
2023 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2028 static NICKSERV_FUNC(cmd_resetpass
)
2030 struct handle_info
*hi
;
2031 char crypted
[MD5_CRYPT_LENGTH
];
2034 NICKSERV_MIN_PARMS(3);
2035 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2039 if (user
->handle_info
) {
2040 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2043 if (IsStamped(user
)) {
2044 /* Unauthenticated users might still have been stamped
2045 previously and could therefore have a hidden host;
2046 do not allow them to activate an account. */
2047 reply("NSMSG_STAMPED_RESETPASS");
2050 if (!(hi
= get_handle_info(argv
[1]))) {
2051 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2054 if (!hi
->email_addr
) {
2055 reply("MSG_SET_EMAIL_ADDR");
2058 cryptpass(argv
[2], crypted
);
2060 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2064 static NICKSERV_FUNC(cmd_cookie
)
2066 struct handle_info
*hi
;
2069 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2072 NICKSERV_MIN_PARMS(3);
2073 if (!(hi
= get_handle_info(argv
[1]))) {
2074 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2080 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2081 reply("NSMSG_HANDLE_SUSPENDED");
2086 reply("NSMSG_NO_COOKIE");
2090 /* Check validity of operation before comparing cookie to
2091 * prohibit guessing by authed users. */
2092 if (user
->handle_info
2093 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2094 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2095 reply("NSMSG_CANNOT_COOKIE");
2099 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2100 reply("NSMSG_BAD_COOKIE");
2104 switch (hi
->cookie
->type
) {
2106 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2107 set_user_handle_info(user
, hi
, 1);
2108 reply("NSMSG_HANDLE_ACTIVATED");
2109 if (nickserv_conf
.sync_log
)
2110 SyncLog("ACCOUNTACC %s", hi
->handle
);
2112 case PASSWORD_CHANGE
:
2113 set_user_handle_info(user
, hi
, 1);
2114 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2115 reply("NSMSG_PASSWORD_CHANGED");
2116 if (nickserv_conf
.sync_log
)
2117 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2120 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2122 * This should only happen if an OREGISTER was sent. Require
2123 * email must be enabled! - SiRVulcaN
2125 if (nickserv_conf
.sync_log
)
2126 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2128 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2129 reply("NSMSG_EMAIL_CHANGED");
2130 if (nickserv_conf
.sync_log
)
2131 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2134 set_user_handle_info(user
, hi
, 1);
2135 reply("NSMSG_AUTH_SUCCESS");
2138 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2139 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2143 nickserv_eat_cookie(hi
->cookie
);
2145 process_adduser_pending(user
);
2150 static NICKSERV_FUNC(cmd_oregnick
) {
2152 struct handle_info
*target
;
2153 struct nick_info
*ni
;
2155 NICKSERV_MIN_PARMS(3);
2156 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2159 if (!is_registerable_nick(nick
)) {
2160 reply("NSMSG_BAD_NICK", nick
);
2163 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2165 reply("NSMSG_NICK_EXISTS", nick
);
2168 register_nick(nick
, target
);
2169 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2173 static NICKSERV_FUNC(cmd_regnick
) {
2175 struct nick_info
*ni
;
2177 if (!is_registerable_nick(user
->nick
)) {
2178 reply("NSMSG_BAD_NICK", user
->nick
);
2181 /* count their nicks, see if it's too many */
2182 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2183 if (n
>= nickserv_conf
.nicks_per_handle
) {
2184 reply("NSMSG_TOO_MANY_NICKS");
2187 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2189 reply("NSMSG_NICK_EXISTS", user
->nick
);
2192 register_nick(user
->nick
, user
->handle_info
);
2193 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2197 static NICKSERV_FUNC(cmd_pass
)
2199 struct handle_info
*hi
;
2200 const char *old_pass
, *new_pass
;
2202 NICKSERV_MIN_PARMS(3);
2203 hi
= user
->handle_info
;
2207 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2208 if (!checkpass(old_pass
, hi
->passwd
)) {
2209 argv
[1] = "BADPASS";
2210 reply("NSMSG_PASSWORD_INVALID");
2213 cryptpass(new_pass
, hi
->passwd
);
2214 if (nickserv_conf
.sync_log
)
2215 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2217 reply("NSMSG_PASS_SUCCESS");
2222 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2225 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2226 for (i
=0; i
<hi
->masks
->used
; i
++) {
2227 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2228 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2233 string_list_append(hi
->masks
, new_mask
);
2234 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2238 static NICKSERV_FUNC(cmd_addmask
)
2241 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2242 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2246 if (!is_gline(argv
[1])) {
2247 reply("NSMSG_MASK_INVALID", argv
[1]);
2250 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2254 static NICKSERV_FUNC(cmd_oaddmask
)
2256 struct handle_info
*hi
;
2258 NICKSERV_MIN_PARMS(3);
2259 if (!(hi
= get_victim_oper(user
, argv
[1])))
2261 return nickserv_addmask(user
, hi
, argv
[2]);
2265 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2268 for (i
=0; i
<hi
->masks
->used
; i
++) {
2269 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2270 char *old_mask
= hi
->masks
->list
[i
];
2271 if (hi
->masks
->used
== 1) {
2272 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2275 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2276 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2281 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2285 static NICKSERV_FUNC(cmd_delmask
)
2287 NICKSERV_MIN_PARMS(2);
2288 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2291 static NICKSERV_FUNC(cmd_odelmask
)
2293 struct handle_info
*hi
;
2294 NICKSERV_MIN_PARMS(3);
2295 if (!(hi
= get_victim_oper(user
, argv
[1])))
2297 return nickserv_delmask(user
, hi
, argv
[2]);
2301 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2302 unsigned int nn
, add
= 1, pos
;
2303 unsigned long added
, removed
, flag
;
2305 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2307 case '+': add
= 1; break;
2308 case '-': add
= 0; break;
2310 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2311 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2314 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2315 /* cheesy avoidance of looking up the flag name.. */
2316 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2319 flag
= 1 << (pos
- 1);
2321 added
|= flag
, removed
&= ~flag
;
2323 removed
|= flag
, added
&= ~flag
;
2328 *premoved
= removed
;
2333 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2335 unsigned long before
, after
, added
, removed
;
2336 struct userNode
*uNode
;
2338 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2339 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2341 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2342 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2344 /* Strip helping flag if they're only a support helper and not
2345 * currently in #support. */
2346 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2347 struct channelList
*schannels
;
2349 schannels
= chanserv_support_channels();
2350 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2351 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2352 if (GetUserMode(schannels
->list
[ii
], uNode
))
2354 if (ii
< schannels
->used
)
2358 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2361 if (after
&& !before
) {
2362 /* Add user to current helper list. */
2363 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2364 userList_append(&curr_helpers
, uNode
);
2365 } else if (!after
&& before
) {
2366 /* Remove user from current helper list. */
2367 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2368 userList_remove(&curr_helpers
, uNode
);
2375 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2379 char *set_display
[] = {
2380 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", /* "STYLE", */
2381 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2382 "FAKEHOST", "TITLE", "EPITHET"
2385 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2386 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2388 /* Do this so options are presented in a consistent order. */
2389 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2390 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2391 opt(user
, hi
, override
, 0, NULL
);
2392 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2395 static NICKSERV_FUNC(cmd_set
)
2397 struct handle_info
*hi
;
2400 hi
= user
->handle_info
;
2402 set_list(user
, hi
, 0);
2405 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2406 reply("NSMSG_INVALID_OPTION", argv
[1]);
2409 return opt(user
, hi
, 0, argc
-1, argv
+1);
2412 static NICKSERV_FUNC(cmd_oset
)
2414 struct handle_info
*hi
;
2417 NICKSERV_MIN_PARMS(2);
2419 if (!(hi
= get_victim_oper(user
, argv
[1])))
2423 set_list(user
, hi
, 0);
2427 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2428 reply("NSMSG_INVALID_OPTION", argv
[2]);
2432 return opt(user
, hi
, 1, argc
-2, argv
+2);
2435 static OPTION_FUNC(opt_info
)
2439 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2441 hi
->infoline
= NULL
;
2443 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2447 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2448 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2452 static OPTION_FUNC(opt_width
)
2455 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2457 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2458 hi
->screen_width
= MIN_LINE_SIZE
;
2459 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2460 hi
->screen_width
= MAX_LINE_SIZE
;
2462 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2466 static OPTION_FUNC(opt_tablewidth
)
2469 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2471 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2472 hi
->table_width
= MIN_LINE_SIZE
;
2473 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2474 hi
->table_width
= MAX_LINE_SIZE
;
2476 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2480 static OPTION_FUNC(opt_color
)
2483 if (enabled_string(argv
[1]))
2484 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2485 else if (disabled_string(argv
[1]))
2486 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2488 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2493 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2497 static OPTION_FUNC(opt_privmsg
)
2500 if (enabled_string(argv
[1]))
2501 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2502 else if (disabled_string(argv
[1]))
2503 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2505 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2510 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2514 static OPTION_FUNC(opt_autohide
)
2517 if (enabled_string(argv
[1]))
2518 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2519 else if (disabled_string(argv
[1]))
2520 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2522 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2527 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2532 static OPTION_FUNC(opt_style)
2537 if (!irccasecmp(argv[1], "Zoot"))
2538 hi->userlist_style = HI_STYLE_ZOOT;
2539 else if (!irccasecmp(argv[1], "def"))
2540 hi->userlist_style = HI_STYLE_DEF;
2543 switch (hi->userlist_style) {
2552 send_message(user, nickserv, "NSMSG_SET_STYLE", style);
2557 static OPTION_FUNC(opt_announcements
)
2562 if (enabled_string(argv
[1]))
2563 hi
->announcements
= 'y';
2564 else if (disabled_string(argv
[1]))
2565 hi
->announcements
= 'n';
2566 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2567 hi
->announcements
= '?';
2569 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2574 switch (hi
->announcements
) {
2575 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2576 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2577 case '?': choice
= "default"; break;
2578 default: choice
= "unknown"; break;
2580 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2584 static OPTION_FUNC(opt_password
)
2587 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2592 cryptpass(argv
[1], hi
->passwd
);
2594 if (nickserv_conf
.sync_log
)
2595 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2597 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2601 static OPTION_FUNC(opt_flags
)
2604 unsigned int ii
, flen
;
2607 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2612 nickserv_apply_flags(user
, hi
, argv
[1]);
2614 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2615 if (hi
->flags
& (1 << ii
))
2616 flags
[flen
++] = handle_flags
[ii
];
2619 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2621 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2625 static OPTION_FUNC(opt_email
)
2629 if (!is_valid_email_addr(argv
[1])) {
2630 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2633 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2634 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2637 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2638 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2640 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2642 nickserv_set_email_addr(hi
, argv
[1]);
2644 nickserv_eat_cookie(hi
->cookie
);
2645 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2648 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2652 static OPTION_FUNC(opt_maxlogins
)
2654 unsigned char maxlogins
;
2656 maxlogins
= strtoul(argv
[1], NULL
, 0);
2657 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2658 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2661 hi
->maxlogins
= maxlogins
;
2663 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2664 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2668 static OPTION_FUNC(opt_language
)
2670 struct language
*lang
;
2672 lang
= language_find(argv
[1]);
2673 if (irccasecmp(lang
->name
, argv
[1]))
2674 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2675 hi
->language
= lang
;
2677 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2682 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2683 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2685 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2686 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2687 && (user
->handle_info
->opserv_level
< 1000))) {
2688 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2691 if ((user
->handle_info
->opserv_level
< new_level
)
2692 || ((user
->handle_info
->opserv_level
== new_level
)
2693 && (user
->handle_info
->opserv_level
< 1000))) {
2694 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2697 if (user
->handle_info
== target
) {
2698 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2701 if (target
->opserv_level
== new_level
)
2703 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2704 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2705 target
->opserv_level
= new_level
;
2709 static OPTION_FUNC(opt_level
)
2714 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2718 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2719 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2723 static OPTION_FUNC(opt_epithet
)
2725 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2728 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2732 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2736 if ((epithet
[0] == '*') && !epithet
[1])
2739 hi
->epithet
= strdup(epithet
);
2743 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2745 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2749 static OPTION_FUNC(opt_title
)
2753 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2755 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2760 if (strchr(title
, '.')) {
2761 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2764 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2765 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2766 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2771 if (!strcmp(title
, "*")) {
2772 hi
->fakehost
= NULL
;
2774 hi
->fakehost
= malloc(strlen(title
)+2);
2775 hi
->fakehost
[0] = '.';
2776 strcpy(hi
->fakehost
+1, title
);
2779 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2780 title
= hi
->fakehost
+ 1;
2784 title
= user_find_message(user
, "MSG_NONE");
2785 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2789 static OPTION_FUNC(opt_fakehost
)
2793 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2795 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2800 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2801 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2805 if (!strcmp(fake
, "*"))
2806 hi
->fakehost
= NULL
;
2808 hi
->fakehost
= strdup(fake
);
2809 fake
= hi
->fakehost
;
2812 fake
= generate_fakehost(hi
);
2814 fake
= user_find_message(user
, "MSG_NONE");
2815 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2819 static NICKSERV_FUNC(cmd_reclaim
)
2821 struct handle_info
*hi
;
2822 struct nick_info
*ni
;
2823 struct userNode
*victim
;
2825 NICKSERV_MIN_PARMS(2);
2826 hi
= user
->handle_info
;
2827 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2829 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2832 if (ni
->owner
!= user
->handle_info
) {
2833 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2836 victim
= GetUserH(ni
->nick
);
2838 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2841 if (victim
== user
) {
2842 reply("NSMSG_NICK_USER_YOU");
2845 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2846 switch (nickserv_conf
.reclaim_action
) {
2847 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2848 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2849 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2850 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2855 static NICKSERV_FUNC(cmd_unregnick
)
2858 struct handle_info
*hi
;
2859 struct nick_info
*ni
;
2861 hi
= user
->handle_info
;
2862 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2863 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2865 reply("NSMSG_UNKNOWN_NICK", nick
);
2868 if (hi
!= ni
->owner
) {
2869 reply("NSMSG_NOT_YOUR_NICK", nick
);
2872 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2877 static NICKSERV_FUNC(cmd_ounregnick
)
2879 struct nick_info
*ni
;
2881 NICKSERV_MIN_PARMS(2);
2882 if (!(ni
= get_nick_info(argv
[1]))) {
2883 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2886 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2887 reply("MSG_USER_OUTRANKED", ni
->nick
);
2890 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2895 static NICKSERV_FUNC(cmd_unregister
)
2897 struct handle_info
*hi
;
2900 NICKSERV_MIN_PARMS(2);
2901 hi
= user
->handle_info
;
2904 if (checkpass(passwd
, hi
->passwd
)) {
2905 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2908 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2909 reply("NSMSG_PASSWORD_INVALID");
2914 static NICKSERV_FUNC(cmd_ounregister
)
2916 struct handle_info
*hi
;
2918 NICKSERV_MIN_PARMS(2);
2919 if (!(hi
= get_victim_oper(user
, argv
[1])))
2921 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2925 static NICKSERV_FUNC(cmd_status
)
2927 if (nickserv_conf
.disable_nicks
) {
2928 reply("NSMSG_GLOBAL_STATS_NONICK",
2929 dict_size(nickserv_handle_dict
));
2931 if (user
->handle_info
) {
2933 struct nick_info
*ni
;
2934 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2935 reply("NSMSG_HANDLE_STATS", cnt
);
2937 reply("NSMSG_HANDLE_NONE");
2939 reply("NSMSG_GLOBAL_STATS",
2940 dict_size(nickserv_handle_dict
),
2941 dict_size(nickserv_nick_dict
));
2946 static NICKSERV_FUNC(cmd_ghost
)
2948 struct userNode
*target
;
2949 char reason
[MAXLEN
];
2951 NICKSERV_MIN_PARMS(2);
2952 if (!(target
= GetUserH(argv
[1]))) {
2953 reply("MSG_NICK_UNKNOWN", argv
[1]);
2956 if (target
== user
) {
2957 reply("NSMSG_CANNOT_GHOST_SELF");
2960 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2961 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2964 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2965 DelUser(target
, nickserv
, 1, reason
);
2966 reply("NSMSG_GHOST_KILLED", argv
[1]);
2970 static NICKSERV_FUNC(cmd_vacation
)
2972 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2973 reply("NSMSG_ON_VACATION");
2978 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2980 struct handle_info
*hi
;
2983 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2985 #ifdef WITH_PROTOCOL_BAHAMUT
2988 saxdb_start_record(ctx
, iter_key(it
), 0);
2989 if (hi
->announcements
!= '?') {
2990 flags
[0] = hi
->announcements
;
2992 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2995 struct handle_cookie
*cookie
= hi
->cookie
;
2998 switch (cookie
->type
) {
2999 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3000 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3001 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3002 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3003 default: type
= NULL
; break;
3006 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3007 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3008 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3010 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3011 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3012 saxdb_end_record(ctx
);
3016 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3018 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3020 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3024 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3025 if (hi
->flags
& (1 << ii
))
3026 flags
[flen
++] = handle_flags
[ii
];
3028 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3030 #ifdef WITH_PROTOCOL_BAHAMUT
3031 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3034 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3035 if (hi
->last_quit_host
[0])
3036 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3037 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3038 if (hi
->masks
->used
)
3039 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3041 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3043 struct string_list
*slist
;
3044 struct nick_info
*ni
;
3046 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3047 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3048 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3052 if (hi
->opserv_level
)
3053 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3054 if (hi
->language
!= lang_C
)
3055 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3056 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3057 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3058 if (hi
->screen_width
)
3059 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3060 if (hi
->table_width
)
3061 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3062 flags
[0] = hi
->userlist_style
;
3064 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3065 saxdb_end_record(ctx
);
3070 static handle_merge_func_t
*handle_merge_func_list
;
3071 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3074 reg_handle_merge_func(handle_merge_func_t func
)
3076 if (handle_merge_func_used
== handle_merge_func_size
) {
3077 if (handle_merge_func_size
) {
3078 handle_merge_func_size
<<= 1;
3079 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3081 handle_merge_func_size
= 8;
3082 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3085 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3088 static NICKSERV_FUNC(cmd_merge
)
3090 struct handle_info
*hi_from
, *hi_to
;
3091 struct userNode
*last_user
;
3092 struct userData
*cList
, *cListNext
;
3093 unsigned int ii
, jj
, n
;
3094 char buffer
[MAXLEN
];
3096 NICKSERV_MIN_PARMS(3);
3098 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3100 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3102 if (hi_to
== hi_from
) {
3103 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3107 for (n
=0; n
<handle_merge_func_used
; n
++)
3108 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3110 /* Append "from" handle's nicks to "to" handle's nick list. */
3112 struct nick_info
*last_ni
;
3113 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3114 last_ni
->next
= hi_from
->nicks
;
3116 while (hi_from
->nicks
) {
3117 hi_from
->nicks
->owner
= hi_to
;
3118 hi_from
->nicks
= hi_from
->nicks
->next
;
3121 /* Merge the hostmasks. */
3122 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3123 char *mask
= hi_from
->masks
->list
[ii
];
3124 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3125 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3127 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3128 string_list_append(hi_to
->masks
, strdup(mask
));
3131 /* Merge the lists of authed users. */
3133 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3134 last_user
->next_authed
= hi_from
->users
;
3136 hi_to
->users
= hi_from
->users
;
3138 /* Repoint the old "from" handle's users. */
3139 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3140 last_user
->handle_info
= hi_to
;
3142 hi_from
->users
= NULL
;
3144 /* Merge channel userlists. */
3145 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3146 struct userData
*cList2
;
3147 cListNext
= cList
->u_next
;
3148 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3149 if (cList
->channel
== cList2
->channel
)
3151 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3152 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
);
3153 /* keep cList2 in hi_to; remove cList from hi_from */
3154 del_channel_user(cList
, 1);
3157 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
);
3158 /* remove the lower-ranking cList2 from hi_to */
3159 del_channel_user(cList2
, 1);
3161 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3163 /* cList needs to be moved from hi_from to hi_to */
3164 cList
->handle
= hi_to
;
3165 /* Remove from linked list for hi_from */
3166 assert(!cList
->u_prev
);
3167 hi_from
->channels
= cList
->u_next
;
3169 cList
->u_next
->u_prev
= cList
->u_prev
;
3170 /* Add to linked list for hi_to */
3171 cList
->u_prev
= NULL
;
3172 cList
->u_next
= hi_to
->channels
;
3173 if (hi_to
->channels
)
3174 hi_to
->channels
->u_prev
= cList
;
3175 hi_to
->channels
= cList
;
3179 /* Do they get an OpServ level promotion? */
3180 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3181 hi_to
->opserv_level
= hi_from
->opserv_level
;
3183 /* What about last seen time? */
3184 if (hi_from
->lastseen
> hi_to
->lastseen
)
3185 hi_to
->lastseen
= hi_from
->lastseen
;
3187 /* Does a fakehost carry over? (This intentionally doesn't set it
3188 * for users previously attached to hi_to. They'll just have to
3191 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3192 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3194 /* Notify of success. */
3195 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3196 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3197 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3199 /* Unregister the "from" handle. */
3200 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3205 struct nickserv_discrim
{
3206 unsigned int limit
, min_level
, max_level
;
3207 unsigned long flags_on
, flags_off
;
3208 time_t min_registered
, max_registered
;
3210 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3211 const char *nickmask
;
3212 const char *hostmask
;
3213 const char *handlemask
;
3214 const char *emailmask
;
3217 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3219 struct discrim_apply_info
{
3220 struct nickserv_discrim
*discrim
;
3221 discrim_search_func func
;
3222 struct userNode
*source
;
3223 unsigned int matched
;
3226 static struct nickserv_discrim
*
3227 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3230 struct nickserv_discrim
*discrim
;
3232 discrim
= malloc(sizeof(*discrim
));
3233 memset(discrim
, 0, sizeof(*discrim
));
3234 discrim
->min_level
= 0;
3235 discrim
->max_level
= ~0;
3236 discrim
->limit
= 50;
3237 discrim
->min_registered
= 0;
3238 discrim
->max_registered
= INT_MAX
;
3239 discrim
->lastseen
= now
;
3241 for (i
=0; i
<argc
; i
++) {
3242 if (i
== argc
- 1) {
3243 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3246 if (!irccasecmp(argv
[i
], "limit")) {
3247 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3248 } else if (!irccasecmp(argv
[i
], "flags")) {
3249 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3250 } else if (!irccasecmp(argv
[i
], "registered")) {
3251 const char *cmp
= argv
[++i
];
3252 if (cmp
[0] == '<') {
3253 if (cmp
[1] == '=') {
3254 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3256 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3258 } else if (cmp
[0] == '=') {
3259 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3260 } else if (cmp
[0] == '>') {
3261 if (cmp
[1] == '=') {
3262 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3264 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3267 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3269 } else if (!irccasecmp(argv
[i
], "seen")) {
3270 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3271 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3272 discrim
->nickmask
= argv
[++i
];
3273 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3275 if (!irccasecmp(argv
[i
], "exact")) {
3276 if (i
== argc
- 1) {
3277 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3280 discrim
->hostmask_type
= EXACT
;
3281 } else if (!irccasecmp(argv
[i
], "subset")) {
3282 if (i
== argc
- 1) {
3283 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3286 discrim
->hostmask_type
= SUBSET
;
3287 } else if (!irccasecmp(argv
[i
], "superset")) {
3288 if (i
== argc
- 1) {
3289 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3292 discrim
->hostmask_type
= SUPERSET
;
3293 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3294 if (i
== argc
- 1) {
3295 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3298 discrim
->hostmask_type
= LASTQUIT
;
3301 discrim
->hostmask_type
= SUPERSET
;
3303 discrim
->hostmask
= argv
[++i
];
3304 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3305 if (!irccasecmp(argv
[++i
], "*")) {
3306 discrim
->handlemask
= 0;
3308 discrim
->handlemask
= argv
[i
];
3310 } else if (!irccasecmp(argv
[i
], "email")) {
3311 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3312 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3314 } else if (!irccasecmp(argv
[++i
], "*")) {
3315 discrim
->emailmask
= 0;
3317 discrim
->emailmask
= argv
[i
];
3319 } else if (!irccasecmp(argv
[i
], "access")) {
3320 const char *cmp
= argv
[++i
];
3321 if (cmp
[0] == '<') {
3322 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3323 if (cmp
[1] == '=') {
3324 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3326 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3328 } else if (cmp
[0] == '=') {
3329 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3330 } else if (cmp
[0] == '>') {
3331 if (cmp
[1] == '=') {
3332 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3334 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3337 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3340 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3351 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3353 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3354 || (discrim
->flags_off
& hi
->flags
)
3355 || (discrim
->min_registered
> hi
->registered
)
3356 || (discrim
->max_registered
< hi
->registered
)
3357 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3358 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3359 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3360 || (discrim
->min_level
> hi
->opserv_level
)
3361 || (discrim
->max_level
< hi
->opserv_level
)) {
3364 if (discrim
->hostmask
) {
3366 for (i
=0; i
<hi
->masks
->used
; i
++) {
3367 const char *mask
= hi
->masks
->list
[i
];
3368 if ((discrim
->hostmask_type
== SUBSET
)
3369 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3370 else if ((discrim
->hostmask_type
== EXACT
)
3371 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3372 else if ((discrim
->hostmask_type
== SUPERSET
)
3373 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3374 else if ((discrim
->hostmask_type
== LASTQUIT
)
3375 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3377 if (i
==hi
->masks
->used
) return 0;
3379 if (discrim
->nickmask
) {
3380 struct nick_info
*nick
= hi
->nicks
;
3382 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3385 if (!nick
) return 0;
3391 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3393 dict_iterator_t it
, next
;
3394 unsigned int matched
;
3396 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3397 it
&& (matched
< discrim
->limit
);
3399 next
= iter_next(it
);
3400 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3401 dsf(source
, iter_data(it
));
3409 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3411 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3415 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3420 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3422 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3423 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3427 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3429 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3430 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3431 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3432 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3433 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3437 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3439 struct handle_info_list hil
;
3440 struct helpfile_table tbl
;
3445 memset(&hil
, 0, sizeof(hil
));
3446 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3447 struct handle_info
*hi
= iter_data(it
);
3448 if (hi
->opserv_level
)
3449 handle_info_list_append(&hil
, hi
);
3451 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3452 tbl
.length
= hil
.used
+ 1;
3454 tbl
.flags
= TABLE_NO_FREE
;
3455 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3456 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3459 for (ii
= 0; ii
< hil
.used
; ) {
3460 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3461 ary
[0] = hil
.list
[ii
]->handle
;
3462 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3463 tbl
.contents
[++ii
] = ary
;
3465 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3466 reply("MSG_MATCH_COUNT", hil
.used
);
3467 for (ii
= 0; ii
< hil
.used
; ii
++)
3468 free(tbl
.contents
[ii
]);
3473 static NICKSERV_FUNC(cmd_search
)
3475 struct nickserv_discrim
*discrim
;
3476 discrim_search_func action
;
3477 struct svccmd
*subcmd
;
3478 unsigned int matches
;
3481 NICKSERV_MIN_PARMS(3);
3482 sprintf(buf
, "search %s", argv
[1]);
3483 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3484 if (!irccasecmp(argv
[1], "print"))
3485 action
= search_print_func
;
3486 else if (!irccasecmp(argv
[1], "count"))
3487 action
= search_count_func
;
3488 else if (!irccasecmp(argv
[1], "unregister"))
3489 action
= search_unregister_func
;
3491 reply("NSMSG_INVALID_ACTION", argv
[1]);
3495 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3498 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3502 if (action
== search_print_func
)
3503 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3504 else if (action
== search_count_func
)
3505 discrim
->limit
= INT_MAX
;
3507 matches
= nickserv_discrim_search(discrim
, action
, user
);
3510 reply("MSG_MATCH_COUNT", matches
);
3512 reply("MSG_NO_MATCHES");
3518 static MODCMD_FUNC(cmd_checkpass
)
3520 struct handle_info
*hi
;
3522 NICKSERV_MIN_PARMS(3);
3523 if (!(hi
= get_handle_info(argv
[1]))) {
3524 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3527 if (checkpass(argv
[2], hi
->passwd
))
3528 reply("CHECKPASS_YES");
3530 reply("CHECKPASS_NO");
3536 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3539 struct string_list
*masks
, *slist
;
3540 struct handle_info
*hi
;
3541 struct userNode
*authed_users
;
3542 struct userData
*channels
;
3543 unsigned long int id
;
3547 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3548 id
= str
? strtoul(str
, NULL
, 0) : 0;
3549 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3551 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3554 if ((hi
= get_handle_info(handle
))) {
3555 authed_users
= hi
->users
;
3556 channels
= hi
->channels
;
3558 hi
->channels
= NULL
;
3559 dict_remove(nickserv_handle_dict
, hi
->handle
);
3561 authed_users
= NULL
;
3564 hi
= register_handle(handle
, str
, id
);
3566 hi
->users
= authed_users
;
3567 while (authed_users
) {
3568 authed_users
->handle_info
= hi
;
3569 authed_users
= authed_users
->next_authed
;
3572 hi
->channels
= channels
;
3573 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3574 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3575 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3576 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3577 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3578 hi
->language
= language_find(str
? str
: "C");
3579 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3580 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3581 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3583 hi
->infoline
= strdup(str
);
3584 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3585 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3586 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3587 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3588 /* We want to read the nicks even if disable_nicks is set. This is so
3589 * that we don't lose the nick data entirely. */
3590 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3592 for (ii
=0; ii
<slist
->used
; ii
++)
3593 register_nick(slist
->list
[ii
], hi
);
3595 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3597 for (ii
=0; str
[ii
]; ii
++)
3598 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3600 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3601 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3602 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3603 hi
->announcements
= str
? str
[0] : '?';
3604 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3605 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3606 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3607 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3608 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3610 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3612 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3613 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3615 nickserv_set_email_addr(hi
, str
);
3616 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3618 hi
->epithet
= strdup(str
);
3619 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3621 hi
->fakehost
= strdup(str
);
3622 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3624 const char *data
, *type
, *expires
, *cookie_str
;
3625 struct handle_cookie
*cookie
;
3627 cookie
= calloc(1, sizeof(*cookie
));
3628 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3629 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3630 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3631 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3632 if (!type
|| !expires
|| !cookie_str
) {
3633 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3636 if (!irccasecmp(type
, KEY_ACTIVATION
))
3637 cookie
->type
= ACTIVATION
;
3638 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3639 cookie
->type
= PASSWORD_CHANGE
;
3640 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3641 cookie
->type
= EMAIL_CHANGE
;
3642 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3643 cookie
->type
= ALLOWAUTH
;
3645 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3648 cookie
->expires
= strtoul(expires
, NULL
, 0);
3649 if (cookie
->expires
< now
)
3652 cookie
->data
= strdup(data
);
3653 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3657 nickserv_bake_cookie(cookie
);
3659 nickserv_free_cookie(cookie
);
3664 nickserv_saxdb_read(dict_t db
) {
3666 struct record_data
*rd
;
3668 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3670 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3675 static NICKSERV_FUNC(cmd_mergedb
)
3677 struct timeval start
, stop
;
3680 NICKSERV_MIN_PARMS(2);
3681 gettimeofday(&start
, NULL
);
3682 if (!(db
= parse_database(argv
[1]))) {
3683 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3686 nickserv_saxdb_read(db
);
3688 gettimeofday(&stop
, NULL
);
3689 stop
.tv_sec
-= start
.tv_sec
;
3690 stop
.tv_usec
-= start
.tv_usec
;
3691 if (stop
.tv_usec
< 0) {
3693 stop
.tv_usec
+= 1000000;
3695 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3700 expire_handles(UNUSED_ARG(void *data
))
3702 dict_iterator_t it
, next
;
3704 struct handle_info
*hi
;
3706 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3707 next
= iter_next(it
);
3709 if ((hi
->opserv_level
> 0)
3711 || HANDLE_FLAGGED(hi
, FROZEN
)
3712 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3715 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3716 if ((now
- hi
->lastseen
) > expiry
) {
3717 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3718 nickserv_unregister_handle(hi
, NULL
, NULL
);
3722 if (nickserv_conf
.handle_expire_frequency
)
3723 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3727 nickserv_load_dict(const char *fname
)
3731 if (!(file
= fopen(fname
, "r"))) {
3732 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3735 while (!feof(file
)) {
3736 fgets(line
, sizeof(line
), file
);
3739 if (line
[strlen(line
)-1] == '\n')
3740 line
[strlen(line
)-1] = 0;
3741 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3744 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3747 static enum reclaim_action
3748 reclaim_action_from_string(const char *str
) {
3750 return RECLAIM_NONE
;
3751 else if (!irccasecmp(str
, "warn"))
3752 return RECLAIM_WARN
;
3753 else if (!irccasecmp(str
, "svsnick"))
3754 return RECLAIM_SVSNICK
;
3755 else if (!irccasecmp(str
, "kill"))
3756 return RECLAIM_KILL
;
3758 return RECLAIM_NONE
;
3762 nickserv_conf_read(void)
3764 dict_t conf_node
, child
;
3768 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3769 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3772 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3774 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3775 if (nickserv_conf
.valid_handle_regex_set
)
3776 regfree(&nickserv_conf
.valid_handle_regex
);
3778 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3779 nickserv_conf
.valid_handle_regex_set
= !err
;
3780 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3782 nickserv_conf
.valid_handle_regex_set
= 0;
3784 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3785 if (nickserv_conf
.valid_nick_regex_set
)
3786 regfree(&nickserv_conf
.valid_nick_regex
);
3788 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3789 nickserv_conf
.valid_nick_regex_set
= !err
;
3790 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3792 nickserv_conf
.valid_nick_regex_set
= 0;
3794 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3796 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3797 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3798 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3799 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3800 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3801 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3802 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3803 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3804 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3805 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3806 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3807 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3808 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3809 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3810 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3811 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3812 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3813 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3814 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3815 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3816 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3817 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3818 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3819 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3820 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3822 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3823 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3824 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3826 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3827 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3828 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3830 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3831 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3832 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3833 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3834 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3835 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3836 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3837 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3838 if (!nickserv_conf
.disable_nicks
) {
3839 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3840 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3841 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3842 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3843 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3844 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3845 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3846 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3848 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3849 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3850 const char *key
= iter_key(it
), *value
;
3854 if (!strncasecmp(key
, "uc_", 3))
3855 flag
= toupper(key
[3]);
3856 else if (!strncasecmp(key
, "lc_", 3))
3857 flag
= tolower(key
[3]);
3861 if ((pos
= handle_inverse_flags
[flag
])) {
3862 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3863 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3866 if (nickserv_conf
.weak_password_dict
)
3867 dict_delete(nickserv_conf
.weak_password_dict
);
3868 nickserv_conf
.weak_password_dict
= dict_new();
3869 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3870 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3871 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3872 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3874 nickserv_load_dict(str
);
3875 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3876 if (nickserv
&& str
)
3877 NickChange(nickserv
, str
, 0);
3878 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3879 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3880 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3881 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3882 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3883 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3884 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3885 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3886 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3887 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3888 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3889 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3890 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3891 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3892 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3893 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3894 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3895 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3896 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3897 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3899 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
3900 nickserv_conf
.auto_oper
= str
? str
: "";
3902 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
3903 nickserv_conf
.auto_admin
= str
? str
: "";
3905 str
= conf_get_data("server/network", RECDB_QSTRING
);
3906 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3907 if (!nickserv_conf
.auth_policer_params
) {
3908 nickserv_conf
.auth_policer_params
= policer_params_new();
3909 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3910 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3912 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3913 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3914 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3918 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3920 char newnick
[NICKLEN
+1];
3929 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3931 case RECLAIM_SVSNICK
:
3933 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3934 } while (GetUserH(newnick
));
3935 irc_svsnick(nickserv
, user
, newnick
);
3938 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3939 irc_kill(nickserv
, user
, msg
);
3945 nickserv_reclaim_p(void *data
) {
3946 struct userNode
*user
= data
;
3947 struct nick_info
*ni
= get_nick_info(user
->nick
);
3949 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3953 check_user_nick(struct userNode
*user
) {
3954 struct nick_info
*ni
;
3955 user
->modes
&= ~FLAGS_REGNICK
;
3956 if (!(ni
= get_nick_info(user
->nick
)))
3958 if (user
->handle_info
== ni
->owner
) {
3959 user
->modes
|= FLAGS_REGNICK
;
3963 if (nickserv_conf
.warn_nick_owned
)
3964 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3965 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3967 if (nickserv_conf
.auto_reclaim_delay
)
3968 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3970 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3975 handle_new_user(struct userNode
*user
)
3977 return check_user_nick(user
);
3981 handle_account(struct userNode
*user
, const char *stamp
)
3983 struct handle_info
*hi
;
3986 #ifdef WITH_PROTOCOL_P10
3987 time_t timestamp
= 0;
3989 colon
= strchr(stamp
, ':');
3990 if(colon
&& colon
[1])
3993 timestamp
= atoi(colon
+1);
3995 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3996 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3998 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
);
4002 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4003 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4007 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4010 set_user_handle_info(user
, hi
, 0);
4012 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4017 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4019 struct handle_info
*hi
;
4021 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4022 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4023 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4025 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4026 check_user_nick(user
);
4030 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4032 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4033 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4034 set_user_handle_info(user
, NULL
, 0);
4037 static struct modcmd
*
4038 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4040 if (min_level
> 0) {
4042 sprintf(buf
, "%u", min_level
);
4043 if (must_be_qualified
) {
4044 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4046 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4048 } else if (min_level
== 0) {
4049 if (must_be_qualified
) {
4050 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4052 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4055 if (must_be_qualified
) {
4056 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4058 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4064 nickserv_db_cleanup(void)
4066 unreg_del_user_func(nickserv_remove_user
);
4067 userList_clean(&curr_helpers
);
4068 policer_params_delete(nickserv_conf
.auth_policer_params
);
4069 dict_delete(nickserv_handle_dict
);
4070 dict_delete(nickserv_nick_dict
);
4071 dict_delete(nickserv_opt_dict
);
4072 dict_delete(nickserv_allow_auth_dict
);
4073 dict_delete(nickserv_email_dict
);
4074 dict_delete(nickserv_id_dict
);
4075 dict_delete(nickserv_conf
.weak_password_dict
);
4076 free(auth_func_list
);
4077 free(unreg_func_list
);
4079 free(allowauth_func_list
);
4080 free(handle_merge_func_list
);
4081 free(failpw_func_list
);
4082 if (nickserv_conf
.valid_handle_regex_set
)
4083 regfree(&nickserv_conf
.valid_handle_regex
);
4084 if (nickserv_conf
.valid_nick_regex_set
)
4085 regfree(&nickserv_conf
.valid_nick_regex
);
4089 init_nickserv(const char *nick
)
4092 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4093 reg_new_user_func(handle_new_user
);
4094 reg_nick_change_func(handle_nick_change
);
4095 reg_del_user_func(nickserv_remove_user
);
4096 reg_account_func(handle_account
);
4098 /* set up handle_inverse_flags */
4099 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4100 for (i
=0; handle_flags
[i
]; i
++) {
4101 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4102 flag_access_levels
[i
] = 0;
4105 conf_register_reload(nickserv_conf_read
);
4106 nickserv_opt_dict
= dict_new();
4107 nickserv_email_dict
= dict_new();
4108 dict_set_free_keys(nickserv_email_dict
, free
);
4109 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4111 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4112 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4113 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4114 * a big pain to disable since its nolonger in the config file. ) -Rubin
4116 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4117 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4118 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4119 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4120 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4121 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4122 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4123 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4124 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4125 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4126 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4127 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4128 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4129 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4130 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4131 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4132 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4133 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4134 if (!nickserv_conf
.disable_nicks
) {
4135 /* nick management commands */
4136 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4137 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4138 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4139 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4140 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4141 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4143 if (nickserv_conf
.email_enabled
) {
4144 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4145 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4146 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4147 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4148 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4149 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4151 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4152 /* miscellaneous commands */
4153 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4154 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4155 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4156 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4157 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4159 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4160 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4161 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4162 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4163 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4164 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4165 /* dict_insert(nickserv_opt_dict, "STYLE", opt_style); */
4166 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4167 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4168 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4169 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4170 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4171 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4172 if (nickserv_conf
.titlehost_suffix
) {
4173 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4174 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4176 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4177 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4178 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4180 nickserv_handle_dict
= dict_new();
4181 dict_set_free_keys(nickserv_handle_dict
, free
);
4182 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4184 nickserv_id_dict
= dict_new();
4185 dict_set_free_keys(nickserv_id_dict
, free
);
4187 nickserv_nick_dict
= dict_new();
4188 dict_set_free_data(nickserv_nick_dict
, free
);
4190 nickserv_allow_auth_dict
= dict_new();
4192 userList_init(&curr_helpers
);
4195 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4196 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4197 nickserv_service
= service_register(nickserv
);
4199 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4200 reg_exit_func(nickserv_db_cleanup
);
4201 if(nickserv_conf
.handle_expire_frequency
)
4202 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4203 message_register_table(msgtab
);