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(4);
1373 if (!is_valid_handle(argv
[1])) {
1374 reply("NSMSG_BAD_HANDLE", argv
[1]);
1378 if (strchr(argv
[3], '@')) {
1379 mask
= canonicalize_hostmask(strdup(argv
[3]));
1381 settee
= GetUserH(argv
[4]);
1383 reply("MSG_NICK_UNKNOWN", argv
[4]);
1390 } else if ((settee
= GetUserH(argv
[3]))) {
1391 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1393 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1396 if (settee
&& settee
->handle_info
) {
1397 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1401 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1405 string_list_append(hi
->masks
, mask
);
1409 static NICKSERV_FUNC(cmd_handleinfo
)
1412 unsigned int i
, pos
=0, herelen
;
1413 struct userNode
*target
, *next_un
;
1414 struct handle_info
*hi
;
1415 const char *nsmsg_none
;
1418 if (!(hi
= user
->handle_info
)) {
1419 reply("NSMSG_MUST_AUTH");
1422 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1426 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1427 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1429 #ifdef WITH_PROTOCOL_BAHAMUT
1430 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1432 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1435 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1436 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1438 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1441 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1442 if (HANDLE_FLAGGED(hi
, FROZEN
))
1443 reply("NSMSG_HANDLEINFO_VACATION");
1445 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1446 struct do_not_register
*dnr
;
1447 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1448 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1449 if (!oper_outranks(user
, hi
))
1451 } else if (hi
!= user
->handle_info
) {
1452 reply("NSMSG_HANDLEINFO_END");
1456 if (nickserv_conf
.email_enabled
)
1457 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1461 switch (hi
->cookie
->type
) {
1462 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1463 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1464 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1465 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1466 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1472 unsigned long flen
= 1;
1473 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1475 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1476 if (hi
->flags
& 1 << i
)
1477 flags
[flen
++] = handle_flags
[i
];
1479 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1481 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1484 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1485 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1486 || (hi
->opserv_level
> 0)) {
1487 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1491 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1493 if (hi
->last_quit_host
[0])
1494 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1496 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1498 if (nickserv_conf
.disable_nicks
) {
1499 /* nicks disabled; don't show anything about registered nicks */
1500 } else if (hi
->nicks
) {
1501 struct nick_info
*ni
, *next_ni
;
1502 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1503 herelen
= strlen(ni
->nick
);
1504 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1506 goto print_nicks_buff
;
1510 memcpy(buff
+pos
, ni
->nick
, herelen
);
1511 pos
+= herelen
; buff
[pos
++] = ' ';
1515 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1520 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1523 if (hi
->masks
->used
) {
1524 for (i
=0; i
< hi
->masks
->used
; i
++) {
1525 herelen
= strlen(hi
->masks
->list
[i
]);
1526 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1528 goto print_mask_buff
;
1530 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1531 pos
+= herelen
; buff
[pos
++] = ' ';
1532 if (i
+1 == hi
->masks
->used
) {
1535 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1540 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1544 struct userData
*channel
, *next
;
1547 for (channel
= hi
->channels
; channel
; channel
= next
) {
1548 next
= channel
->u_next
;
1549 name
= channel
->channel
->channel
->name
;
1550 herelen
= strlen(name
);
1551 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1553 goto print_chans_buff
;
1555 if (IsUserSuspended(channel
))
1557 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1561 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1566 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1569 for (target
= hi
->users
; target
; target
= next_un
) {
1570 herelen
= strlen(target
->nick
);
1571 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1573 goto print_cnick_buff
;
1575 next_un
= target
->next_authed
;
1577 memcpy(buff
+pos
, target
->nick
, herelen
);
1578 pos
+= herelen
; buff
[pos
++] = ' ';
1582 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1587 reply("NSMSG_HANDLEINFO_END");
1591 static NICKSERV_FUNC(cmd_userinfo
)
1593 struct userNode
*target
;
1595 NICKSERV_MIN_PARMS(2);
1596 if (!(target
= GetUserH(argv
[1]))) {
1597 reply("MSG_NICK_UNKNOWN", argv
[1]);
1600 if (target
->handle_info
)
1601 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1603 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1607 static NICKSERV_FUNC(cmd_nickinfo
)
1609 struct nick_info
*ni
;
1611 NICKSERV_MIN_PARMS(2);
1612 if (!(ni
= get_nick_info(argv
[1]))) {
1613 reply("MSG_NICK_UNKNOWN", argv
[1]);
1616 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1620 static NICKSERV_FUNC(cmd_rename_handle
)
1622 struct handle_info
*hi
;
1623 struct userNode
*uNode
;
1624 char msgbuf
[MAXLEN
], *old_handle
;
1627 NICKSERV_MIN_PARMS(3);
1628 if (!(hi
= get_victim_oper(user
, argv
[1])))
1630 if (!is_valid_handle(argv
[2])) {
1631 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1634 if (get_handle_info(argv
[2])) {
1635 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1638 if(strlen(argv
[2]) > 15)
1640 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1644 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1645 hi
->handle
= strdup(argv
[2]);
1646 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1647 for (nn
=0; nn
<rf_list_used
; nn
++)
1648 rf_list
[nn
](hi
, old_handle
);
1649 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1652 if (nickserv_conf
.sync_log
) {
1653 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1654 irc_rename(uNode
, hi
->handle
);
1656 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1659 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1660 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1665 static failpw_func_t
*failpw_func_list
;
1666 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1669 reg_failpw_func(failpw_func_t func
)
1671 if (failpw_func_used
== failpw_func_size
) {
1672 if (failpw_func_size
) {
1673 failpw_func_size
<<= 1;
1674 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1676 failpw_func_size
= 8;
1677 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1680 failpw_func_list
[failpw_func_used
++] = func
;
1684 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1686 * called by nefariouses enhanced AC login-on-connect code
1689 struct handle_info
*loc_auth(char *handle
, char *password
)
1691 int pw_arg
, used
, maxlogins
;
1694 struct handle_info
*hi
;
1695 struct userNode
*other
;
1697 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1703 /* We don't know the users hostname, or anything because they
1704 * havn't registered yet. So we can only allow LOC if your
1705 * account has *@* as a hostmask.
1707 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1709 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1718 /* Responses from here on look up the language used by the handle they asked about. */
1719 if (!checkpass(password
, hi
->passwd
)) {
1722 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1725 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1726 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1727 if (++used
>= maxlogins
) {
1734 static NICKSERV_FUNC(cmd_auth
)
1736 int pw_arg
, used
, maxlogins
;
1737 struct handle_info
*hi
;
1739 struct userNode
*other
;
1741 if (user
->handle_info
) {
1742 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1745 if (IsStamped(user
)) {
1746 /* Unauthenticated users might still have been stamped
1747 previously and could therefore have a hidden host;
1748 do not allow them to authenticate. */
1749 reply("NSMSG_STAMPED_AUTH");
1753 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1755 } else if (argc
== 2) {
1756 if (nickserv_conf
.disable_nicks
) {
1757 if (!(hi
= get_handle_info(user
->nick
))) {
1758 reply("NSMSG_HANDLE_NOT_FOUND");
1762 /* try to look up their handle from their nick */
1763 struct nick_info
*ni
;
1764 ni
= get_nick_info(user
->nick
);
1766 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1773 reply("MSG_MISSING_PARAMS", argv
[0]);
1774 svccmd_send_help_brief(user
, nickserv
, cmd
);
1778 reply("NSMSG_HANDLE_NOT_FOUND");
1781 /* Responses from here on look up the language used by the handle they asked about. */
1782 passwd
= argv
[pw_arg
];
1783 if (!valid_user_for(user
, hi
)) {
1784 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1785 send_message_type(4, user
, cmd
->parent
->bot
,
1786 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1789 send_message_type(4, user
, cmd
->parent
->bot
,
1790 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1792 argv
[pw_arg
] = "BADMASK";
1795 if (!checkpass(passwd
, hi
->passwd
)) {
1797 send_message_type(4, user
, cmd
->parent
->bot
,
1798 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1799 argv
[pw_arg
] = "BADPASS";
1800 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1801 if (nickserv_conf
.autogag_enabled
) {
1802 if (!user
->auth_policer
.params
) {
1803 user
->auth_policer
.last_req
= now
;
1804 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1806 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1808 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1809 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1810 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1812 argv
[pw_arg
] = "GAGGED";
1817 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1818 send_message_type(4, user
, cmd
->parent
->bot
,
1819 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1820 argv
[pw_arg
] = "SUSPENDED";
1823 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1824 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1825 if (++used
>= maxlogins
) {
1826 send_message_type(4, user
, cmd
->parent
->bot
,
1827 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1829 argv
[pw_arg
] = "MAXLOGINS";
1834 set_user_handle_info(user
, hi
, 1);
1835 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1836 reply("NSMSG_PLEASE_SET_EMAIL");
1837 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1838 reply("NSMSG_WEAK_PASSWORD");
1839 if (hi
->passwd
[0] != '$')
1840 cryptpass(passwd
, hi
->passwd
);
1842 /* If a channel was waiting for this user to auth,
1843 * finish adding them */
1844 process_adduser_pending(user
);
1846 reply("NSMSG_AUTH_SUCCESS");
1849 /* Set +x if autohide is on */
1850 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
1851 irc_umode(user
, "+x");
1853 if(!IsOper(user
)) /* If they arnt already opered.. */
1855 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
1856 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
1858 irc_umode(user
,nickserv_conf
.auto_admin
);
1859 reply("NSMSG_AUTO_OPER_ADMIN");
1861 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
1863 irc_umode(user
,nickserv_conf
.auto_oper
);
1864 reply("NSMSG_AUTO_OPER");
1868 /* Wipe out the pass for the logs */
1869 argv
[pw_arg
] = "****";
1873 static allowauth_func_t
*allowauth_func_list
;
1874 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1877 reg_allowauth_func(allowauth_func_t func
)
1879 if (allowauth_func_used
== allowauth_func_size
) {
1880 if (allowauth_func_size
) {
1881 allowauth_func_size
<<= 1;
1882 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1884 allowauth_func_size
= 8;
1885 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1888 allowauth_func_list
[allowauth_func_used
++] = func
;
1891 static NICKSERV_FUNC(cmd_allowauth
)
1893 struct userNode
*target
;
1894 struct handle_info
*hi
;
1897 NICKSERV_MIN_PARMS(2);
1898 if (!(target
= GetUserH(argv
[1]))) {
1899 reply("MSG_NICK_UNKNOWN", argv
[1]);
1902 if (target
->handle_info
) {
1903 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1906 if (IsStamped(target
)) {
1907 /* Unauthenticated users might still have been stamped
1908 previously and could therefore have a hidden host;
1909 do not allow them to authenticate to an account. */
1910 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1915 else if (!(hi
= get_handle_info(argv
[2]))) {
1916 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1920 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1921 reply("MSG_USER_OUTRANKED", hi
->handle
);
1924 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1925 || (hi
->opserv_level
> 0))
1926 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1927 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1930 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1931 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1932 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1933 if (nickserv_conf
.email_enabled
)
1934 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1936 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1937 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1939 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1941 for (n
=0; n
<allowauth_func_used
; n
++)
1942 allowauth_func_list
[n
](user
, target
, hi
);
1946 static NICKSERV_FUNC(cmd_authcookie
)
1948 struct handle_info
*hi
;
1950 NICKSERV_MIN_PARMS(2);
1951 if (user
->handle_info
) {
1952 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1955 if (IsStamped(user
)) {
1956 /* Unauthenticated users might still have been stamped
1957 previously and could therefore have a hidden host;
1958 do not allow them to authenticate to an account. */
1959 reply("NSMSG_STAMPED_AUTHCOOKIE");
1962 if (!(hi
= get_handle_info(argv
[1]))) {
1963 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1966 if (!hi
->email_addr
) {
1967 reply("MSG_SET_EMAIL_ADDR");
1970 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1974 static NICKSERV_FUNC(cmd_delcookie
)
1976 struct handle_info
*hi
;
1978 hi
= user
->handle_info
;
1980 reply("NSMSG_NO_COOKIE");
1983 switch (hi
->cookie
->type
) {
1986 reply("NSMSG_MUST_TIME_OUT");
1989 nickserv_eat_cookie(hi
->cookie
);
1990 reply("NSMSG_ATE_COOKIE");
1996 static NICKSERV_FUNC(cmd_odelcookie
)
1998 struct handle_info
*hi
;
2000 NICKSERV_MIN_PARMS(2);
2002 if (!(hi
= get_victim_oper(user
, argv
[1])))
2006 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2010 nickserv_eat_cookie(hi
->cookie
);
2011 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2016 static NICKSERV_FUNC(cmd_resetpass
)
2018 struct handle_info
*hi
;
2019 char crypted
[MD5_CRYPT_LENGTH
];
2022 NICKSERV_MIN_PARMS(3);
2023 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2027 if (user
->handle_info
) {
2028 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2031 if (IsStamped(user
)) {
2032 /* Unauthenticated users might still have been stamped
2033 previously and could therefore have a hidden host;
2034 do not allow them to activate an account. */
2035 reply("NSMSG_STAMPED_RESETPASS");
2038 if (!(hi
= get_handle_info(argv
[1]))) {
2039 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2042 if (!hi
->email_addr
) {
2043 reply("MSG_SET_EMAIL_ADDR");
2046 cryptpass(argv
[2], crypted
);
2048 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2052 static NICKSERV_FUNC(cmd_cookie
)
2054 struct handle_info
*hi
;
2057 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2060 NICKSERV_MIN_PARMS(3);
2061 if (!(hi
= get_handle_info(argv
[1]))) {
2062 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2068 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2069 reply("NSMSG_HANDLE_SUSPENDED");
2074 reply("NSMSG_NO_COOKIE");
2078 /* Check validity of operation before comparing cookie to
2079 * prohibit guessing by authed users. */
2080 if (user
->handle_info
2081 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2082 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2083 reply("NSMSG_CANNOT_COOKIE");
2087 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2088 reply("NSMSG_BAD_COOKIE");
2092 switch (hi
->cookie
->type
) {
2094 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2095 set_user_handle_info(user
, hi
, 1);
2096 reply("NSMSG_HANDLE_ACTIVATED");
2097 if (nickserv_conf
.sync_log
)
2098 SyncLog("ACCOUNTACC %s", hi
->handle
);
2100 case PASSWORD_CHANGE
:
2101 set_user_handle_info(user
, hi
, 1);
2102 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2103 reply("NSMSG_PASSWORD_CHANGED");
2104 if (nickserv_conf
.sync_log
)
2105 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2108 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2110 * This should only happen if an OREGISTER was sent. Require
2111 * email must be enabled! - SiRVulcaN
2113 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2115 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2116 reply("NSMSG_EMAIL_CHANGED");
2117 if (nickserv_conf
.sync_log
)
2118 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2121 set_user_handle_info(user
, hi
, 1);
2122 reply("NSMSG_AUTH_SUCCESS");
2125 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2126 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2130 nickserv_eat_cookie(hi
->cookie
);
2132 process_adduser_pending(user
);
2137 static NICKSERV_FUNC(cmd_oregnick
) {
2139 struct handle_info
*target
;
2140 struct nick_info
*ni
;
2142 NICKSERV_MIN_PARMS(3);
2143 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2146 if (!is_registerable_nick(nick
)) {
2147 reply("NSMSG_BAD_NICK", nick
);
2150 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2152 reply("NSMSG_NICK_EXISTS", nick
);
2155 register_nick(nick
, target
);
2156 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2160 static NICKSERV_FUNC(cmd_regnick
) {
2162 struct nick_info
*ni
;
2164 if (!is_registerable_nick(user
->nick
)) {
2165 reply("NSMSG_BAD_NICK", user
->nick
);
2168 /* count their nicks, see if it's too many */
2169 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2170 if (n
>= nickserv_conf
.nicks_per_handle
) {
2171 reply("NSMSG_TOO_MANY_NICKS");
2174 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2176 reply("NSMSG_NICK_EXISTS", user
->nick
);
2179 register_nick(user
->nick
, user
->handle_info
);
2180 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2184 static NICKSERV_FUNC(cmd_pass
)
2186 struct handle_info
*hi
;
2187 const char *old_pass
, *new_pass
;
2189 NICKSERV_MIN_PARMS(3);
2190 hi
= user
->handle_info
;
2194 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2195 if (!checkpass(old_pass
, hi
->passwd
)) {
2196 argv
[1] = "BADPASS";
2197 reply("NSMSG_PASSWORD_INVALID");
2200 cryptpass(new_pass
, hi
->passwd
);
2201 if (nickserv_conf
.sync_log
)
2202 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2204 reply("NSMSG_PASS_SUCCESS");
2209 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2212 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2213 for (i
=0; i
<hi
->masks
->used
; i
++) {
2214 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2215 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2220 string_list_append(hi
->masks
, new_mask
);
2221 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2225 static NICKSERV_FUNC(cmd_addmask
)
2228 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2229 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2233 if (!is_gline(argv
[1])) {
2234 reply("NSMSG_MASK_INVALID", argv
[1]);
2237 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2241 static NICKSERV_FUNC(cmd_oaddmask
)
2243 struct handle_info
*hi
;
2245 NICKSERV_MIN_PARMS(3);
2246 if (!(hi
= get_victim_oper(user
, argv
[1])))
2248 return nickserv_addmask(user
, hi
, argv
[2]);
2252 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2255 for (i
=0; i
<hi
->masks
->used
; i
++) {
2256 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2257 char *old_mask
= hi
->masks
->list
[i
];
2258 if (hi
->masks
->used
== 1) {
2259 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2262 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2263 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2268 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2272 static NICKSERV_FUNC(cmd_delmask
)
2274 NICKSERV_MIN_PARMS(2);
2275 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2278 static NICKSERV_FUNC(cmd_odelmask
)
2280 struct handle_info
*hi
;
2281 NICKSERV_MIN_PARMS(3);
2282 if (!(hi
= get_victim_oper(user
, argv
[1])))
2284 return nickserv_delmask(user
, hi
, argv
[2]);
2288 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2289 unsigned int nn
, add
= 1, pos
;
2290 unsigned long added
, removed
, flag
;
2292 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2294 case '+': add
= 1; break;
2295 case '-': add
= 0; break;
2297 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2298 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2301 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2302 /* cheesy avoidance of looking up the flag name.. */
2303 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2306 flag
= 1 << (pos
- 1);
2308 added
|= flag
, removed
&= ~flag
;
2310 removed
|= flag
, added
&= ~flag
;
2315 *premoved
= removed
;
2320 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2322 unsigned long before
, after
, added
, removed
;
2323 struct userNode
*uNode
;
2325 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2326 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2328 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2329 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2331 /* Strip helping flag if they're only a support helper and not
2332 * currently in #support. */
2333 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2334 struct channelList
*schannels
;
2336 schannels
= chanserv_support_channels();
2337 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2338 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2339 if (GetUserMode(schannels
->list
[ii
], uNode
))
2341 if (ii
< schannels
->used
)
2345 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2348 if (after
&& !before
) {
2349 /* Add user to current helper list. */
2350 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2351 userList_append(&curr_helpers
, uNode
);
2352 } else if (!after
&& before
) {
2353 /* Remove user from current helper list. */
2354 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2355 userList_remove(&curr_helpers
, uNode
);
2362 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2366 char *set_display
[] = {
2367 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", /* "STYLE", */
2368 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2369 "FAKEHOST", "TITLE", "EPITHET"
2372 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2373 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2375 /* Do this so options are presented in a consistent order. */
2376 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2377 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2378 opt(user
, hi
, override
, 0, NULL
);
2379 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2382 static NICKSERV_FUNC(cmd_set
)
2384 struct handle_info
*hi
;
2387 hi
= user
->handle_info
;
2389 set_list(user
, hi
, 0);
2392 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2393 reply("NSMSG_INVALID_OPTION", argv
[1]);
2396 return opt(user
, hi
, 0, argc
-1, argv
+1);
2399 static NICKSERV_FUNC(cmd_oset
)
2401 struct handle_info
*hi
;
2404 NICKSERV_MIN_PARMS(2);
2406 if (!(hi
= get_victim_oper(user
, argv
[1])))
2410 set_list(user
, hi
, 0);
2414 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2415 reply("NSMSG_INVALID_OPTION", argv
[2]);
2419 return opt(user
, hi
, 1, argc
-2, argv
+2);
2422 static OPTION_FUNC(opt_info
)
2426 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2428 hi
->infoline
= NULL
;
2430 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2434 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2435 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2439 static OPTION_FUNC(opt_width
)
2442 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2444 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2445 hi
->screen_width
= MIN_LINE_SIZE
;
2446 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2447 hi
->screen_width
= MAX_LINE_SIZE
;
2449 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2453 static OPTION_FUNC(opt_tablewidth
)
2456 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2458 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2459 hi
->table_width
= MIN_LINE_SIZE
;
2460 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2461 hi
->table_width
= MAX_LINE_SIZE
;
2463 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2467 static OPTION_FUNC(opt_color
)
2470 if (enabled_string(argv
[1]))
2471 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2472 else if (disabled_string(argv
[1]))
2473 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2475 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2480 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2484 static OPTION_FUNC(opt_privmsg
)
2487 if (enabled_string(argv
[1]))
2488 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2489 else if (disabled_string(argv
[1]))
2490 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2492 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2497 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2501 static OPTION_FUNC(opt_autohide
)
2504 if (enabled_string(argv
[1]))
2505 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2506 else if (disabled_string(argv
[1]))
2507 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2509 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2514 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2519 static OPTION_FUNC(opt_style)
2524 if (!irccasecmp(argv[1], "Zoot"))
2525 hi->userlist_style = HI_STYLE_ZOOT;
2526 else if (!irccasecmp(argv[1], "def"))
2527 hi->userlist_style = HI_STYLE_DEF;
2530 switch (hi->userlist_style) {
2539 send_message(user, nickserv, "NSMSG_SET_STYLE", style);
2544 static OPTION_FUNC(opt_announcements
)
2549 if (enabled_string(argv
[1]))
2550 hi
->announcements
= 'y';
2551 else if (disabled_string(argv
[1]))
2552 hi
->announcements
= 'n';
2553 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2554 hi
->announcements
= '?';
2556 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2561 switch (hi
->announcements
) {
2562 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2563 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2564 case '?': choice
= "default"; break;
2565 default: choice
= "unknown"; break;
2567 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2571 static OPTION_FUNC(opt_password
)
2574 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2579 cryptpass(argv
[1], hi
->passwd
);
2581 if (nickserv_conf
.sync_log
)
2582 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2584 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2588 static OPTION_FUNC(opt_flags
)
2591 unsigned int ii
, flen
;
2594 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2599 nickserv_apply_flags(user
, hi
, argv
[1]);
2601 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2602 if (hi
->flags
& (1 << ii
))
2603 flags
[flen
++] = handle_flags
[ii
];
2606 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2608 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2612 static OPTION_FUNC(opt_email
)
2616 if (!is_valid_email_addr(argv
[1])) {
2617 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2620 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2621 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2624 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2625 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2627 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2629 nickserv_set_email_addr(hi
, argv
[1]);
2631 nickserv_eat_cookie(hi
->cookie
);
2632 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2635 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2639 static OPTION_FUNC(opt_maxlogins
)
2641 unsigned char maxlogins
;
2643 maxlogins
= strtoul(argv
[1], NULL
, 0);
2644 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2645 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2648 hi
->maxlogins
= maxlogins
;
2650 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2651 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2655 static OPTION_FUNC(opt_language
)
2657 struct language
*lang
;
2659 lang
= language_find(argv
[1]);
2660 if (irccasecmp(lang
->name
, argv
[1]))
2661 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2662 hi
->language
= lang
;
2664 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2669 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2670 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2672 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2673 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2674 && (user
->handle_info
->opserv_level
< 1000))) {
2675 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2678 if ((user
->handle_info
->opserv_level
< new_level
)
2679 || ((user
->handle_info
->opserv_level
== new_level
)
2680 && (user
->handle_info
->opserv_level
< 1000))) {
2681 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2684 if (user
->handle_info
== target
) {
2685 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2688 if (target
->opserv_level
== new_level
)
2690 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2691 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2692 target
->opserv_level
= new_level
;
2696 static OPTION_FUNC(opt_level
)
2701 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2705 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2706 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2710 static OPTION_FUNC(opt_epithet
)
2712 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2715 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2719 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2723 if ((epithet
[0] == '*') && !epithet
[1])
2726 hi
->epithet
= strdup(epithet
);
2730 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2732 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2736 static OPTION_FUNC(opt_title
)
2740 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2742 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2747 if (strchr(title
, '.')) {
2748 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2751 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2752 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2753 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2758 if (!strcmp(title
, "*")) {
2759 hi
->fakehost
= NULL
;
2761 hi
->fakehost
= malloc(strlen(title
)+2);
2762 hi
->fakehost
[0] = '.';
2763 strcpy(hi
->fakehost
+1, title
);
2766 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2767 title
= hi
->fakehost
+ 1;
2771 title
= user_find_message(user
, "MSG_NONE");
2772 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2776 static OPTION_FUNC(opt_fakehost
)
2780 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2782 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2787 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2788 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2792 if (!strcmp(fake
, "*"))
2793 hi
->fakehost
= NULL
;
2795 hi
->fakehost
= strdup(fake
);
2796 fake
= hi
->fakehost
;
2799 fake
= generate_fakehost(hi
);
2801 fake
= user_find_message(user
, "MSG_NONE");
2802 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2806 static NICKSERV_FUNC(cmd_reclaim
)
2808 struct handle_info
*hi
;
2809 struct nick_info
*ni
;
2810 struct userNode
*victim
;
2812 NICKSERV_MIN_PARMS(2);
2813 hi
= user
->handle_info
;
2814 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2816 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2819 if (ni
->owner
!= user
->handle_info
) {
2820 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2823 victim
= GetUserH(ni
->nick
);
2825 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2828 if (victim
== user
) {
2829 reply("NSMSG_NICK_USER_YOU");
2832 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2833 switch (nickserv_conf
.reclaim_action
) {
2834 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2835 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2836 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2837 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2842 static NICKSERV_FUNC(cmd_unregnick
)
2845 struct handle_info
*hi
;
2846 struct nick_info
*ni
;
2848 hi
= user
->handle_info
;
2849 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2850 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2852 reply("NSMSG_UNKNOWN_NICK", nick
);
2855 if (hi
!= ni
->owner
) {
2856 reply("NSMSG_NOT_YOUR_NICK", nick
);
2859 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2864 static NICKSERV_FUNC(cmd_ounregnick
)
2866 struct nick_info
*ni
;
2868 NICKSERV_MIN_PARMS(2);
2869 if (!(ni
= get_nick_info(argv
[1]))) {
2870 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2873 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2874 reply("MSG_USER_OUTRANKED", ni
->nick
);
2877 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2882 static NICKSERV_FUNC(cmd_unregister
)
2884 struct handle_info
*hi
;
2887 NICKSERV_MIN_PARMS(2);
2888 hi
= user
->handle_info
;
2891 if (checkpass(passwd
, hi
->passwd
)) {
2892 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2895 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2896 reply("NSMSG_PASSWORD_INVALID");
2901 static NICKSERV_FUNC(cmd_ounregister
)
2903 struct handle_info
*hi
;
2905 NICKSERV_MIN_PARMS(2);
2906 if (!(hi
= get_victim_oper(user
, argv
[1])))
2908 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2912 static NICKSERV_FUNC(cmd_status
)
2914 if (nickserv_conf
.disable_nicks
) {
2915 reply("NSMSG_GLOBAL_STATS_NONICK",
2916 dict_size(nickserv_handle_dict
));
2918 if (user
->handle_info
) {
2920 struct nick_info
*ni
;
2921 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2922 reply("NSMSG_HANDLE_STATS", cnt
);
2924 reply("NSMSG_HANDLE_NONE");
2926 reply("NSMSG_GLOBAL_STATS",
2927 dict_size(nickserv_handle_dict
),
2928 dict_size(nickserv_nick_dict
));
2933 static NICKSERV_FUNC(cmd_ghost
)
2935 struct userNode
*target
;
2936 char reason
[MAXLEN
];
2938 NICKSERV_MIN_PARMS(2);
2939 if (!(target
= GetUserH(argv
[1]))) {
2940 reply("MSG_NICK_UNKNOWN", argv
[1]);
2943 if (target
== user
) {
2944 reply("NSMSG_CANNOT_GHOST_SELF");
2947 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2948 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2951 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2952 DelUser(target
, nickserv
, 1, reason
);
2953 reply("NSMSG_GHOST_KILLED", argv
[1]);
2957 static NICKSERV_FUNC(cmd_vacation
)
2959 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2960 reply("NSMSG_ON_VACATION");
2965 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2967 struct handle_info
*hi
;
2970 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2972 #ifdef WITH_PROTOCOL_BAHAMUT
2975 saxdb_start_record(ctx
, iter_key(it
), 0);
2976 if (hi
->announcements
!= '?') {
2977 flags
[0] = hi
->announcements
;
2979 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2982 struct handle_cookie
*cookie
= hi
->cookie
;
2985 switch (cookie
->type
) {
2986 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2987 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2988 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2989 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2990 default: type
= NULL
; break;
2993 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2994 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2995 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2997 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2998 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2999 saxdb_end_record(ctx
);
3003 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3005 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3007 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3011 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3012 if (hi
->flags
& (1 << ii
))
3013 flags
[flen
++] = handle_flags
[ii
];
3015 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3017 #ifdef WITH_PROTOCOL_BAHAMUT
3018 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3021 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3022 if (hi
->last_quit_host
[0])
3023 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3024 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3025 if (hi
->masks
->used
)
3026 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3028 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3030 struct string_list
*slist
;
3031 struct nick_info
*ni
;
3033 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3034 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3035 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3039 if (hi
->opserv_level
)
3040 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3041 if (hi
->language
!= lang_C
)
3042 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3043 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3044 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3045 if (hi
->screen_width
)
3046 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3047 if (hi
->table_width
)
3048 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3049 flags
[0] = hi
->userlist_style
;
3051 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3052 saxdb_end_record(ctx
);
3057 static handle_merge_func_t
*handle_merge_func_list
;
3058 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3061 reg_handle_merge_func(handle_merge_func_t func
)
3063 if (handle_merge_func_used
== handle_merge_func_size
) {
3064 if (handle_merge_func_size
) {
3065 handle_merge_func_size
<<= 1;
3066 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3068 handle_merge_func_size
= 8;
3069 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3072 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3075 static NICKSERV_FUNC(cmd_merge
)
3077 struct handle_info
*hi_from
, *hi_to
;
3078 struct userNode
*last_user
;
3079 struct userData
*cList
, *cListNext
;
3080 unsigned int ii
, jj
, n
;
3081 char buffer
[MAXLEN
];
3083 NICKSERV_MIN_PARMS(3);
3085 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3087 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3089 if (hi_to
== hi_from
) {
3090 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3094 for (n
=0; n
<handle_merge_func_used
; n
++)
3095 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3097 /* Append "from" handle's nicks to "to" handle's nick list. */
3099 struct nick_info
*last_ni
;
3100 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3101 last_ni
->next
= hi_from
->nicks
;
3103 while (hi_from
->nicks
) {
3104 hi_from
->nicks
->owner
= hi_to
;
3105 hi_from
->nicks
= hi_from
->nicks
->next
;
3108 /* Merge the hostmasks. */
3109 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3110 char *mask
= hi_from
->masks
->list
[ii
];
3111 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3112 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3114 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3115 string_list_append(hi_to
->masks
, strdup(mask
));
3118 /* Merge the lists of authed users. */
3120 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3121 last_user
->next_authed
= hi_from
->users
;
3123 hi_to
->users
= hi_from
->users
;
3125 /* Repoint the old "from" handle's users. */
3126 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3127 last_user
->handle_info
= hi_to
;
3129 hi_from
->users
= NULL
;
3131 /* Merge channel userlists. */
3132 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3133 struct userData
*cList2
;
3134 cListNext
= cList
->u_next
;
3135 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3136 if (cList
->channel
== cList2
->channel
)
3138 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3139 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
);
3140 /* keep cList2 in hi_to; remove cList from hi_from */
3141 del_channel_user(cList
, 1);
3144 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
);
3145 /* remove the lower-ranking cList2 from hi_to */
3146 del_channel_user(cList2
, 1);
3148 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3150 /* cList needs to be moved from hi_from to hi_to */
3151 cList
->handle
= hi_to
;
3152 /* Remove from linked list for hi_from */
3153 assert(!cList
->u_prev
);
3154 hi_from
->channels
= cList
->u_next
;
3156 cList
->u_next
->u_prev
= cList
->u_prev
;
3157 /* Add to linked list for hi_to */
3158 cList
->u_prev
= NULL
;
3159 cList
->u_next
= hi_to
->channels
;
3160 if (hi_to
->channels
)
3161 hi_to
->channels
->u_prev
= cList
;
3162 hi_to
->channels
= cList
;
3166 /* Do they get an OpServ level promotion? */
3167 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3168 hi_to
->opserv_level
= hi_from
->opserv_level
;
3170 /* What about last seen time? */
3171 if (hi_from
->lastseen
> hi_to
->lastseen
)
3172 hi_to
->lastseen
= hi_from
->lastseen
;
3174 /* Does a fakehost carry over? (This intentionally doesn't set it
3175 * for users previously attached to hi_to. They'll just have to
3178 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3179 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3181 /* Notify of success. */
3182 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3183 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3184 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3186 /* Unregister the "from" handle. */
3187 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3192 struct nickserv_discrim
{
3193 unsigned int limit
, min_level
, max_level
;
3194 unsigned long flags_on
, flags_off
;
3195 time_t min_registered
, max_registered
;
3197 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3198 const char *nickmask
;
3199 const char *hostmask
;
3200 const char *handlemask
;
3201 const char *emailmask
;
3204 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3206 struct discrim_apply_info
{
3207 struct nickserv_discrim
*discrim
;
3208 discrim_search_func func
;
3209 struct userNode
*source
;
3210 unsigned int matched
;
3213 static struct nickserv_discrim
*
3214 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3217 struct nickserv_discrim
*discrim
;
3219 discrim
= malloc(sizeof(*discrim
));
3220 memset(discrim
, 0, sizeof(*discrim
));
3221 discrim
->min_level
= 0;
3222 discrim
->max_level
= ~0;
3223 discrim
->limit
= 50;
3224 discrim
->min_registered
= 0;
3225 discrim
->max_registered
= INT_MAX
;
3226 discrim
->lastseen
= now
;
3228 for (i
=0; i
<argc
; i
++) {
3229 if (i
== argc
- 1) {
3230 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3233 if (!irccasecmp(argv
[i
], "limit")) {
3234 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3235 } else if (!irccasecmp(argv
[i
], "flags")) {
3236 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3237 } else if (!irccasecmp(argv
[i
], "registered")) {
3238 const char *cmp
= argv
[++i
];
3239 if (cmp
[0] == '<') {
3240 if (cmp
[1] == '=') {
3241 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3243 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3245 } else if (cmp
[0] == '=') {
3246 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3247 } else if (cmp
[0] == '>') {
3248 if (cmp
[1] == '=') {
3249 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3251 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3254 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3256 } else if (!irccasecmp(argv
[i
], "seen")) {
3257 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3258 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3259 discrim
->nickmask
= argv
[++i
];
3260 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3262 if (!irccasecmp(argv
[i
], "exact")) {
3263 if (i
== argc
- 1) {
3264 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3267 discrim
->hostmask_type
= EXACT
;
3268 } else if (!irccasecmp(argv
[i
], "subset")) {
3269 if (i
== argc
- 1) {
3270 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3273 discrim
->hostmask_type
= SUBSET
;
3274 } else if (!irccasecmp(argv
[i
], "superset")) {
3275 if (i
== argc
- 1) {
3276 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3279 discrim
->hostmask_type
= SUPERSET
;
3280 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3281 if (i
== argc
- 1) {
3282 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3285 discrim
->hostmask_type
= LASTQUIT
;
3288 discrim
->hostmask_type
= SUPERSET
;
3290 discrim
->hostmask
= argv
[++i
];
3291 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3292 if (!irccasecmp(argv
[++i
], "*")) {
3293 discrim
->handlemask
= 0;
3295 discrim
->handlemask
= argv
[i
];
3297 } else if (!irccasecmp(argv
[i
], "email")) {
3298 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3299 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3301 } else if (!irccasecmp(argv
[++i
], "*")) {
3302 discrim
->emailmask
= 0;
3304 discrim
->emailmask
= argv
[i
];
3306 } else if (!irccasecmp(argv
[i
], "access")) {
3307 const char *cmp
= argv
[++i
];
3308 if (cmp
[0] == '<') {
3309 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3310 if (cmp
[1] == '=') {
3311 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3313 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3315 } else if (cmp
[0] == '=') {
3316 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3317 } else if (cmp
[0] == '>') {
3318 if (cmp
[1] == '=') {
3319 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3321 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3324 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3327 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3338 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3340 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3341 || (discrim
->flags_off
& hi
->flags
)
3342 || (discrim
->min_registered
> hi
->registered
)
3343 || (discrim
->max_registered
< hi
->registered
)
3344 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3345 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3346 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3347 || (discrim
->min_level
> hi
->opserv_level
)
3348 || (discrim
->max_level
< hi
->opserv_level
)) {
3351 if (discrim
->hostmask
) {
3353 for (i
=0; i
<hi
->masks
->used
; i
++) {
3354 const char *mask
= hi
->masks
->list
[i
];
3355 if ((discrim
->hostmask_type
== SUBSET
)
3356 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3357 else if ((discrim
->hostmask_type
== EXACT
)
3358 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3359 else if ((discrim
->hostmask_type
== SUPERSET
)
3360 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3361 else if ((discrim
->hostmask_type
== LASTQUIT
)
3362 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3364 if (i
==hi
->masks
->used
) return 0;
3366 if (discrim
->nickmask
) {
3367 struct nick_info
*nick
= hi
->nicks
;
3369 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3372 if (!nick
) return 0;
3378 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3380 dict_iterator_t it
, next
;
3381 unsigned int matched
;
3383 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3384 it
&& (matched
< discrim
->limit
);
3386 next
= iter_next(it
);
3387 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3388 dsf(source
, iter_data(it
));
3396 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3398 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3402 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3407 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3409 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3410 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3414 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3416 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3417 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3418 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3419 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3420 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3424 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3426 struct handle_info_list hil
;
3427 struct helpfile_table tbl
;
3432 memset(&hil
, 0, sizeof(hil
));
3433 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3434 struct handle_info
*hi
= iter_data(it
);
3435 if (hi
->opserv_level
)
3436 handle_info_list_append(&hil
, hi
);
3438 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3439 tbl
.length
= hil
.used
+ 1;
3441 tbl
.flags
= TABLE_NO_FREE
;
3442 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3443 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3446 for (ii
= 0; ii
< hil
.used
; ) {
3447 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3448 ary
[0] = hil
.list
[ii
]->handle
;
3449 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3450 tbl
.contents
[++ii
] = ary
;
3452 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3453 reply("MSG_MATCH_COUNT", hil
.used
);
3454 for (ii
= 0; ii
< hil
.used
; ii
++)
3455 free(tbl
.contents
[ii
]);
3460 static NICKSERV_FUNC(cmd_search
)
3462 struct nickserv_discrim
*discrim
;
3463 discrim_search_func action
;
3464 struct svccmd
*subcmd
;
3465 unsigned int matches
;
3468 NICKSERV_MIN_PARMS(3);
3469 sprintf(buf
, "search %s", argv
[1]);
3470 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3471 if (!irccasecmp(argv
[1], "print"))
3472 action
= search_print_func
;
3473 else if (!irccasecmp(argv
[1], "count"))
3474 action
= search_count_func
;
3475 else if (!irccasecmp(argv
[1], "unregister"))
3476 action
= search_unregister_func
;
3478 reply("NSMSG_INVALID_ACTION", argv
[1]);
3482 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3485 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3489 if (action
== search_print_func
)
3490 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3491 else if (action
== search_count_func
)
3492 discrim
->limit
= INT_MAX
;
3494 matches
= nickserv_discrim_search(discrim
, action
, user
);
3497 reply("MSG_MATCH_COUNT", matches
);
3499 reply("MSG_NO_MATCHES");
3505 static MODCMD_FUNC(cmd_checkpass
)
3507 struct handle_info
*hi
;
3509 NICKSERV_MIN_PARMS(3);
3510 if (!(hi
= get_handle_info(argv
[1]))) {
3511 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3514 if (checkpass(argv
[2], hi
->passwd
))
3515 reply("CHECKPASS_YES");
3517 reply("CHECKPASS_NO");
3523 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3526 struct string_list
*masks
, *slist
;
3527 struct handle_info
*hi
;
3528 struct userNode
*authed_users
;
3529 struct userData
*channels
;
3530 unsigned long int id
;
3534 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3535 id
= str
? strtoul(str
, NULL
, 0) : 0;
3536 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3538 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3541 if ((hi
= get_handle_info(handle
))) {
3542 authed_users
= hi
->users
;
3543 channels
= hi
->channels
;
3545 hi
->channels
= NULL
;
3546 dict_remove(nickserv_handle_dict
, hi
->handle
);
3548 authed_users
= NULL
;
3551 hi
= register_handle(handle
, str
, id
);
3553 hi
->users
= authed_users
;
3554 while (authed_users
) {
3555 authed_users
->handle_info
= hi
;
3556 authed_users
= authed_users
->next_authed
;
3559 hi
->channels
= channels
;
3560 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3561 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3562 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3563 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3564 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3565 hi
->language
= language_find(str
? str
: "C");
3566 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3567 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3568 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3570 hi
->infoline
= strdup(str
);
3571 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3572 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3573 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3574 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3575 /* We want to read the nicks even if disable_nicks is set. This is so
3576 * that we don't lose the nick data entirely. */
3577 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3579 for (ii
=0; ii
<slist
->used
; ii
++)
3580 register_nick(slist
->list
[ii
], hi
);
3582 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3584 for (ii
=0; str
[ii
]; ii
++)
3585 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3587 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3588 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3589 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3590 hi
->announcements
= str
? str
[0] : '?';
3591 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3592 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3593 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3594 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3595 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3597 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3599 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3600 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3602 nickserv_set_email_addr(hi
, str
);
3603 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3605 hi
->epithet
= strdup(str
);
3606 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3608 hi
->fakehost
= strdup(str
);
3609 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3611 const char *data
, *type
, *expires
, *cookie_str
;
3612 struct handle_cookie
*cookie
;
3614 cookie
= calloc(1, sizeof(*cookie
));
3615 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3616 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3617 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3618 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3619 if (!type
|| !expires
|| !cookie_str
) {
3620 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3623 if (!irccasecmp(type
, KEY_ACTIVATION
))
3624 cookie
->type
= ACTIVATION
;
3625 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3626 cookie
->type
= PASSWORD_CHANGE
;
3627 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3628 cookie
->type
= EMAIL_CHANGE
;
3629 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3630 cookie
->type
= ALLOWAUTH
;
3632 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3635 cookie
->expires
= strtoul(expires
, NULL
, 0);
3636 if (cookie
->expires
< now
)
3639 cookie
->data
= strdup(data
);
3640 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3644 nickserv_bake_cookie(cookie
);
3646 nickserv_free_cookie(cookie
);
3651 nickserv_saxdb_read(dict_t db
) {
3653 struct record_data
*rd
;
3655 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3657 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3662 static NICKSERV_FUNC(cmd_mergedb
)
3664 struct timeval start
, stop
;
3667 NICKSERV_MIN_PARMS(2);
3668 gettimeofday(&start
, NULL
);
3669 if (!(db
= parse_database(argv
[1]))) {
3670 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3673 nickserv_saxdb_read(db
);
3675 gettimeofday(&stop
, NULL
);
3676 stop
.tv_sec
-= start
.tv_sec
;
3677 stop
.tv_usec
-= start
.tv_usec
;
3678 if (stop
.tv_usec
< 0) {
3680 stop
.tv_usec
+= 1000000;
3682 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3687 expire_handles(UNUSED_ARG(void *data
))
3689 dict_iterator_t it
, next
;
3691 struct handle_info
*hi
;
3693 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3694 next
= iter_next(it
);
3696 if ((hi
->opserv_level
> 0)
3698 || HANDLE_FLAGGED(hi
, FROZEN
)
3699 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3702 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3703 if ((now
- hi
->lastseen
) > expiry
) {
3704 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3705 nickserv_unregister_handle(hi
, NULL
, NULL
);
3709 if (nickserv_conf
.handle_expire_frequency
)
3710 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3714 nickserv_load_dict(const char *fname
)
3718 if (!(file
= fopen(fname
, "r"))) {
3719 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3722 while (!feof(file
)) {
3723 fgets(line
, sizeof(line
), file
);
3726 if (line
[strlen(line
)-1] == '\n')
3727 line
[strlen(line
)-1] = 0;
3728 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3731 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3734 static enum reclaim_action
3735 reclaim_action_from_string(const char *str
) {
3737 return RECLAIM_NONE
;
3738 else if (!irccasecmp(str
, "warn"))
3739 return RECLAIM_WARN
;
3740 else if (!irccasecmp(str
, "svsnick"))
3741 return RECLAIM_SVSNICK
;
3742 else if (!irccasecmp(str
, "kill"))
3743 return RECLAIM_KILL
;
3745 return RECLAIM_NONE
;
3749 nickserv_conf_read(void)
3751 dict_t conf_node
, child
;
3755 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3756 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3759 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3761 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3762 if (nickserv_conf
.valid_handle_regex_set
)
3763 regfree(&nickserv_conf
.valid_handle_regex
);
3765 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3766 nickserv_conf
.valid_handle_regex_set
= !err
;
3767 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3769 nickserv_conf
.valid_handle_regex_set
= 0;
3771 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3772 if (nickserv_conf
.valid_nick_regex_set
)
3773 regfree(&nickserv_conf
.valid_nick_regex
);
3775 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3776 nickserv_conf
.valid_nick_regex_set
= !err
;
3777 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3779 nickserv_conf
.valid_nick_regex_set
= 0;
3781 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3783 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3784 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3785 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3786 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3787 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3788 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3789 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3790 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3791 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3792 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3793 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3794 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3795 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3796 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3797 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3798 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3799 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3800 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3801 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3802 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3803 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3804 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3805 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3806 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3807 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3809 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3810 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3811 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3813 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3814 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3815 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3817 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3818 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3819 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3820 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3821 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3822 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3823 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3824 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3825 if (!nickserv_conf
.disable_nicks
) {
3826 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3827 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3828 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3829 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3830 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3831 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3832 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3833 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3835 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3836 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3837 const char *key
= iter_key(it
), *value
;
3841 if (!strncasecmp(key
, "uc_", 3))
3842 flag
= toupper(key
[3]);
3843 else if (!strncasecmp(key
, "lc_", 3))
3844 flag
= tolower(key
[3]);
3848 if ((pos
= handle_inverse_flags
[flag
])) {
3849 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3850 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3853 if (nickserv_conf
.weak_password_dict
)
3854 dict_delete(nickserv_conf
.weak_password_dict
);
3855 nickserv_conf
.weak_password_dict
= dict_new();
3856 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3857 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3858 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3859 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3861 nickserv_load_dict(str
);
3862 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3863 if (nickserv
&& str
)
3864 NickChange(nickserv
, str
, 0);
3865 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3866 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3867 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3868 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3869 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3870 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3871 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3872 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3873 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3874 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3875 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3876 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3877 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3878 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3879 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3880 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3881 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3882 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3883 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3884 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3886 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
3887 nickserv_conf
.auto_oper
= str
? str
: "";
3889 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
3890 nickserv_conf
.auto_admin
= str
? str
: "";
3892 str
= conf_get_data("server/network", RECDB_QSTRING
);
3893 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3894 if (!nickserv_conf
.auth_policer_params
) {
3895 nickserv_conf
.auth_policer_params
= policer_params_new();
3896 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3897 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3899 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3900 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3901 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3905 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3907 char newnick
[NICKLEN
+1];
3916 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3918 case RECLAIM_SVSNICK
:
3920 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3921 } while (GetUserH(newnick
));
3922 irc_svsnick(nickserv
, user
, newnick
);
3925 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3926 irc_kill(nickserv
, user
, msg
);
3932 nickserv_reclaim_p(void *data
) {
3933 struct userNode
*user
= data
;
3934 struct nick_info
*ni
= get_nick_info(user
->nick
);
3936 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3940 check_user_nick(struct userNode
*user
) {
3941 struct nick_info
*ni
;
3942 user
->modes
&= ~FLAGS_REGNICK
;
3943 if (!(ni
= get_nick_info(user
->nick
)))
3945 if (user
->handle_info
== ni
->owner
) {
3946 user
->modes
|= FLAGS_REGNICK
;
3950 if (nickserv_conf
.warn_nick_owned
)
3951 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3952 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3954 if (nickserv_conf
.auto_reclaim_delay
)
3955 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3957 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3962 handle_new_user(struct userNode
*user
)
3964 return check_user_nick(user
);
3968 handle_account(struct userNode
*user
, const char *stamp
)
3970 struct handle_info
*hi
;
3973 #ifdef WITH_PROTOCOL_P10
3974 time_t timestamp
= 0;
3976 colon
= strchr(stamp
, ':');
3977 if(colon
&& colon
[1])
3980 timestamp
= atoi(colon
+1);
3982 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3983 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3985 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
);
3989 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3990 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
3994 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3997 set_user_handle_info(user
, hi
, 0);
3999 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4004 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4006 struct handle_info
*hi
;
4008 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4009 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4010 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4012 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4013 check_user_nick(user
);
4017 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4019 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4020 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4021 set_user_handle_info(user
, NULL
, 0);
4024 static struct modcmd
*
4025 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4027 if (min_level
> 0) {
4029 sprintf(buf
, "%u", min_level
);
4030 if (must_be_qualified
) {
4031 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4033 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4035 } else if (min_level
== 0) {
4036 if (must_be_qualified
) {
4037 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4039 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4042 if (must_be_qualified
) {
4043 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4045 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4051 nickserv_db_cleanup(void)
4053 unreg_del_user_func(nickserv_remove_user
);
4054 userList_clean(&curr_helpers
);
4055 policer_params_delete(nickserv_conf
.auth_policer_params
);
4056 dict_delete(nickserv_handle_dict
);
4057 dict_delete(nickserv_nick_dict
);
4058 dict_delete(nickserv_opt_dict
);
4059 dict_delete(nickserv_allow_auth_dict
);
4060 dict_delete(nickserv_email_dict
);
4061 dict_delete(nickserv_id_dict
);
4062 dict_delete(nickserv_conf
.weak_password_dict
);
4063 free(auth_func_list
);
4064 free(unreg_func_list
);
4066 free(allowauth_func_list
);
4067 free(handle_merge_func_list
);
4068 free(failpw_func_list
);
4069 if (nickserv_conf
.valid_handle_regex_set
)
4070 regfree(&nickserv_conf
.valid_handle_regex
);
4071 if (nickserv_conf
.valid_nick_regex_set
)
4072 regfree(&nickserv_conf
.valid_nick_regex
);
4076 init_nickserv(const char *nick
)
4079 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4080 reg_new_user_func(handle_new_user
);
4081 reg_nick_change_func(handle_nick_change
);
4082 reg_del_user_func(nickserv_remove_user
);
4083 reg_account_func(handle_account
);
4085 /* set up handle_inverse_flags */
4086 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4087 for (i
=0; handle_flags
[i
]; i
++) {
4088 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4089 flag_access_levels
[i
] = 0;
4092 conf_register_reload(nickserv_conf_read
);
4093 nickserv_opt_dict
= dict_new();
4094 nickserv_email_dict
= dict_new();
4095 dict_set_free_keys(nickserv_email_dict
, free
);
4096 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4098 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4099 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4100 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4101 * a big pain to disable since its nolonger in the config file. ) -Rubin
4103 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4104 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4105 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4106 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4107 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4108 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4109 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4110 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4111 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4112 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4113 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4114 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4115 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4116 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4117 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4118 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4119 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4120 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4121 if (!nickserv_conf
.disable_nicks
) {
4122 /* nick management commands */
4123 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4124 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4125 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4126 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4127 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4128 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4130 if (nickserv_conf
.email_enabled
) {
4131 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4132 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4133 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4134 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4135 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4136 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4138 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4139 /* miscellaneous commands */
4140 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4141 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4142 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4143 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4144 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4146 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4147 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4148 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4149 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4150 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4151 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4152 /* dict_insert(nickserv_opt_dict, "STYLE", opt_style); */
4153 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4154 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4155 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4156 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4157 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4158 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4159 if (nickserv_conf
.titlehost_suffix
) {
4160 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4161 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4163 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4164 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4165 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4167 nickserv_handle_dict
= dict_new();
4168 dict_set_free_keys(nickserv_handle_dict
, free
);
4169 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4171 nickserv_id_dict
= dict_new();
4172 dict_set_free_keys(nickserv_id_dict
, free
);
4174 nickserv_nick_dict
= dict_new();
4175 dict_set_free_data(nickserv_nick_dict
, free
);
4177 nickserv_allow_auth_dict
= dict_new();
4179 userList_init(&curr_helpers
);
4182 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4183 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4184 nickserv_service
= service_register(nickserv
);
4186 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4187 reg_exit_func(nickserv_db_cleanup
);
4188 if(nickserv_conf
.handle_expire_frequency
)
4189 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4190 message_register_table(msgtab
);