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_PASSWORD", "$bPASSWORD: $b%s" },
292 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
293 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
294 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
295 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
296 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
297 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
298 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
299 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
301 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
302 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
304 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
305 { "NSEMAIL_ACTIVATION_BODY",
306 "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"
308 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
309 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
310 "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"
311 "/msg %3$s@%4$s AUTH %5$s your-password\n"
312 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
313 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
315 "If you did NOT request this account, you do not need to do anything.\n"
316 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
317 { "NSEMAIL_ACTIVATION_BODY_WEB",
318 "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"
320 "To verify your email address and complete the account registration, visit the following URL:\n"
321 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
323 "If you did NOT request this account, you do not need to do anything.\n"
324 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
325 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
326 { "NSEMAIL_PASSWORD_CHANGE_BODY",
327 "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"
328 "To complete the password change, log on to %1$s and type the following command:\n"
329 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
330 "If you did NOT request your password to be changed, you do not need to do anything.\n"
331 "Please contact the %1$s staff if you have questions." },
332 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
333 "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"
334 "To complete the password change, click the following URL:\n"
335 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
336 "If you did NOT request your password to be changed, you do not need to do anything.\n"
337 "Please contact the %1$s staff if you have questions." },
338 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
339 #ifdef stupid_verify_old_email
340 { "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." },
341 { "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." },
343 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
344 { "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." },
345 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
346 { "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." },
347 { "CHECKPASS_YES", "Yes." },
348 { "CHECKPASS_NO", "No." },
352 enum reclaim_action
{
358 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
359 static void nickserv_reclaim_p(void *data
);
362 unsigned int disable_nicks
: 1;
363 unsigned int valid_handle_regex_set
: 1;
364 unsigned int valid_nick_regex_set
: 1;
365 unsigned int autogag_enabled
: 1;
366 unsigned int email_enabled
: 1;
367 unsigned int email_required
: 1;
368 unsigned int default_hostmask
: 1;
369 unsigned int warn_nick_owned
: 1;
370 unsigned int warn_clone_auth
: 1;
371 unsigned int sync_log
: 1;
372 unsigned long nicks_per_handle
;
373 unsigned long password_min_length
;
374 unsigned long password_min_digits
;
375 unsigned long password_min_upper
;
376 unsigned long password_min_lower
;
377 unsigned long db_backup_frequency
;
378 unsigned long handle_expire_frequency
;
379 unsigned long autogag_duration
;
380 unsigned long email_visible_level
;
381 unsigned long cookie_timeout
;
382 unsigned long handle_expire_delay
;
383 unsigned long nochan_handle_expire_delay
;
384 unsigned long modoper_level
;
385 unsigned long set_epithet_level
;
386 unsigned long set_title_level
;
387 unsigned long set_fakehost_level
;
388 unsigned long handles_per_email
;
389 unsigned long email_search_level
;
390 const char *network_name
;
391 const char *titlehost_suffix
;
392 regex_t valid_handle_regex
;
393 regex_t valid_nick_regex
;
394 dict_t weak_password_dict
;
395 struct policer_params
*auth_policer_params
;
396 enum reclaim_action reclaim_action
;
397 enum reclaim_action auto_reclaim_action
;
398 unsigned long auto_reclaim_delay
;
399 unsigned char default_maxlogins
;
400 unsigned char hard_maxlogins
;
401 const char *auto_oper
;
402 const char *auto_admin
;
405 /* We have 2^32 unique account IDs to use. */
406 unsigned long int highest_id
= 0;
409 canonicalize_hostmask(char *mask
)
411 char *out
= mask
, *temp
;
412 if ((temp
= strchr(mask
, '!'))) {
414 while (*temp
) *out
++ = *temp
++;
420 static struct handle_info
*
421 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
423 struct handle_info
*hi
;
425 #ifdef WITH_PROTOCOL_BAHAMUT
426 char id_base64
[IDLEN
+ 1];
429 /* Assign a unique account ID to the account; note that 0 is
430 an invalid account ID. 1 is therefore the first account ID. */
432 id
= 1 + highest_id
++;
434 /* Note: highest_id is and must always be the highest ID. */
435 if(id
> highest_id
) {
439 inttobase64(id_base64
, id
, IDLEN
);
441 /* Make sure an account with the same ID doesn't exist. If a
442 duplicate is found, log some details and assign a new one.
443 This should be impossible, but it never hurts to expect it. */
444 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
445 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
451 hi
= calloc(1, sizeof(*hi
));
452 hi
->userlist_style
= HI_DEFAULT_STYLE
;
453 hi
->announcements
= '?';
454 hi
->handle
= strdup(handle
);
455 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
457 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
459 #ifdef WITH_PROTOCOL_BAHAMUT
461 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
468 register_nick(const char *nick
, struct handle_info
*owner
)
470 struct nick_info
*ni
;
471 ni
= malloc(sizeof(struct nick_info
));
472 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
474 ni
->next
= owner
->nicks
;
476 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
480 delete_nick(struct nick_info
*ni
)
482 struct nick_info
*last
, *next
;
483 struct userNode
*user
;
484 /* Check to see if we should mark a user as unregistered. */
485 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
486 user
->modes
&= ~FLAGS_REGNICK
;
489 /* Remove ni from the nick_info linked list. */
490 if (ni
== ni
->owner
->nicks
) {
491 ni
->owner
->nicks
= ni
->next
;
493 last
= ni
->owner
->nicks
;
499 last
->next
= next
->next
;
501 dict_remove(nickserv_nick_dict
, ni
->nick
);
504 static unreg_func_t
*unreg_func_list
;
505 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
508 reg_unreg_func(unreg_func_t func
)
510 if (unreg_func_used
== unreg_func_size
) {
511 if (unreg_func_size
) {
512 unreg_func_size
<<= 1;
513 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
516 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
519 unreg_func_list
[unreg_func_used
++] = func
;
523 nickserv_free_cookie(void *data
)
525 struct handle_cookie
*cookie
= data
;
526 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
527 if (cookie
->data
) free(cookie
->data
);
532 free_handle_info(void *vhi
)
534 struct handle_info
*hi
= vhi
;
536 #ifdef WITH_PROTOCOL_BAHAMUT
539 inttobase64(id
, hi
->id
, IDLEN
);
540 dict_remove(nickserv_id_dict
, id
);
543 free_string_list(hi
->masks
);
547 delete_nick(hi
->nicks
);
552 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
553 nickserv_free_cookie(hi
->cookie
);
555 if (hi
->email_addr
) {
556 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
557 handle_info_list_remove(hil
, hi
);
559 dict_remove(nickserv_email_dict
, hi
->email_addr
);
564 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
567 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
)
571 for (n
=0; n
<unreg_func_used
; n
++)
572 unreg_func_list
[n
](notify
, hi
);
574 set_user_handle_info(hi
->users
, NULL
, 0);
576 if (nickserv_conf
.disable_nicks
)
577 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
579 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
582 if (nickserv_conf
.sync_log
)
583 SyncLog("UNREGISTER %s", hi
->handle
);
585 dict_remove(nickserv_handle_dict
, hi
->handle
);
589 get_handle_info(const char *handle
)
591 return dict_find(nickserv_handle_dict
, handle
, 0);
595 get_nick_info(const char *nick
)
597 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
601 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
606 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
607 mn
= channel
->members
.list
[nn
];
608 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
615 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
616 if (!user
->handle_info
) {
618 send_message(user
, bot
, "MSG_AUTHENTICATE");
622 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
624 send_message(user
, bot
, "NSMSG_NO_ACCESS");
628 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
630 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
634 if (user
->handle_info
->opserv_level
< min_level
) {
636 send_message(user
, bot
, "NSMSG_NO_ACCESS");
644 is_valid_handle(const char *handle
)
646 struct userNode
*user
;
647 /* cant register a juped nick/service nick as handle, to prevent confusion */
648 user
= GetUserH(handle
);
649 if (user
&& IsLocal(user
))
651 /* check against maximum length */
652 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
654 /* for consistency, only allow account names that could be nicks */
655 if (!is_valid_nick(handle
))
657 /* disallow account names that look like bad words */
658 if (opserv_bad_channel(handle
))
660 /* test either regex or containing all valid chars */
661 if (nickserv_conf
.valid_handle_regex_set
) {
662 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
665 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
666 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
670 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
675 is_registerable_nick(const char *nick
)
677 /* make sure it could be used as an account name */
678 if (!is_valid_handle(nick
))
681 if (strlen(nick
) > NICKLEN
)
683 /* test either regex or as valid handle */
684 if (nickserv_conf
.valid_nick_regex_set
) {
685 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
688 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
689 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
697 is_valid_email_addr(const char *email
)
699 return strchr(email
, '@') != NULL
;
703 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
705 if (hi
->email_addr
) {
706 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
707 return hi
->email_addr
;
717 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
719 struct handle_info
*hi
;
720 struct userNode
*target
;
724 if (!(hi
= get_handle_info(++name
))) {
725 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
730 if (!(target
= GetUserH(name
))) {
731 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
734 if (IsLocal(target
)) {
735 if (IsService(target
))
736 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
738 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
741 if (!(hi
= target
->handle_info
)) {
742 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
750 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
751 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
753 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
754 if ((user
->handle_info
->opserv_level
== 1000)
755 || (user
->handle_info
== hi
)
756 || ((user
->handle_info
->opserv_level
== 0)
757 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
758 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
762 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
766 static struct handle_info
*
767 get_victim_oper(struct userNode
*user
, const char *target
)
769 struct handle_info
*hi
;
770 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
772 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
773 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
776 return oper_outranks(user
, hi
) ? hi
: NULL
;
780 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
784 /* If no hostmasks on the account, allow it. */
785 if (!hi
->masks
->used
)
787 /* If any hostmask matches, allow it. */
788 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
789 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
791 /* If they are allowauthed to this account, allow it (removing the aa). */
792 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
793 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
796 /* The user is not allowed to use this account. */
801 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
804 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
806 if (len
< nickserv_conf
.password_min_length
) {
808 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
811 if (!irccasecmp(pass
, handle
)) {
813 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
816 dict_find(nickserv_conf
.weak_password_dict
, pass
, &i
);
819 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
822 for (i
=0; i
<len
; i
++) {
823 if (isdigit(pass
[i
]))
825 if (isupper(pass
[i
]))
827 if (islower(pass
[i
]))
830 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
831 || (cnt_upper
< nickserv_conf
.password_min_upper
)
832 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
834 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
840 static auth_func_t
*auth_func_list
;
841 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
844 reg_auth_func(auth_func_t func
)
846 if (auth_func_used
== auth_func_size
) {
847 if (auth_func_size
) {
848 auth_func_size
<<= 1;
849 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
852 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
855 auth_func_list
[auth_func_used
++] = func
;
858 static handle_rename_func_t
*rf_list
;
859 static unsigned int rf_list_size
, rf_list_used
;
862 reg_handle_rename_func(handle_rename_func_t func
)
864 if (rf_list_used
== rf_list_size
) {
867 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
870 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
873 rf_list
[rf_list_used
++] = func
;
877 generate_fakehost(struct handle_info
*handle
)
879 extern const char *hidden_host_suffix
;
880 static char buffer
[HOSTLEN
+1];
882 if (!handle
->fakehost
) {
883 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
885 } else if (handle
->fakehost
[0] == '.') {
886 /* A leading dot indicates the stored value is actually a title. */
887 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
890 return handle
->fakehost
;
894 apply_fakehost(struct handle_info
*handle
)
896 struct userNode
*target
;
901 fake
= generate_fakehost(handle
);
902 for (target
= handle
->users
; target
; target
= target
->next_authed
)
903 assign_fakehost(target
, fake
, 1);
907 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
910 struct handle_info
*old_info
;
912 /* This can happen if somebody uses COOKIE while authed, or if
913 * they re-auth to their current handle (which is silly, but users
915 if (user
->handle_info
== hi
)
918 if (user
->handle_info
) {
919 struct userNode
*other
;
922 userList_remove(&curr_helpers
, user
);
924 /* remove from next_authed linked list */
925 if (user
->handle_info
->users
== user
) {
926 user
->handle_info
->users
= user
->next_authed
;
928 for (other
= user
->handle_info
->users
;
929 other
->next_authed
!= user
;
930 other
= other
->next_authed
) ;
931 other
->next_authed
= user
->next_authed
;
933 /* if nobody left on old handle, and they're not an oper, remove !god */
934 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
935 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
936 /* record them as being last seen at this time */
937 user
->handle_info
->lastseen
= now
;
938 /* and record their hostmask */
939 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
941 old_info
= user
->handle_info
;
942 user
->handle_info
= hi
;
943 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
944 HANDLE_CLEAR_FLAG(hi
, HELPING
);
945 for (n
=0; n
<auth_func_used
; n
++)
946 auth_func_list
[n
](user
, old_info
);
948 struct nick_info
*ni
;
950 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
951 if (nickserv_conf
.warn_clone_auth
) {
952 struct userNode
*other
;
953 for (other
= hi
->users
; other
; other
= other
->next_authed
)
954 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
956 user
->next_authed
= hi
->users
;
960 userList_append(&curr_helpers
, user
);
962 if (hi
->fakehost
|| old_info
)
966 #ifdef WITH_PROTOCOL_BAHAMUT
967 /* Stamp users with their account ID. */
969 inttobase64(id
, hi
->id
, IDLEN
);
970 #elif WITH_PROTOCOL_P10
971 /* Stamp users with their account name. */
972 char *id
= hi
->handle
;
974 const char *id
= "???";
976 if (!nickserv_conf
.disable_nicks
) {
977 struct nick_info
*ni
;
978 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
979 if (!irccasecmp(user
->nick
, ni
->nick
)) {
980 user
->modes
|= FLAGS_REGNICK
;
985 StampUser(user
, id
, hi
->registered
);
988 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
989 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
991 /* We cannot clear the user's account ID, unfortunately. */
992 user
->next_authed
= NULL
;
996 static struct handle_info
*
997 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
999 struct handle_info
*hi
;
1000 struct nick_info
*ni
;
1001 char crypted
[MD5_CRYPT_LENGTH
];
1003 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1004 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1008 if(strlen(handle
) > 15)
1010 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1014 if (!is_secure_password(handle
, passwd
, user
))
1017 cryptpass(passwd
, crypted
);
1018 hi
= register_handle(handle
, crypted
, 0);
1019 hi
->masks
= alloc_string_list(1);
1021 hi
->language
= lang_C
;
1022 hi
->registered
= now
;
1024 hi
->flags
= HI_DEFAULT_FLAGS
;
1025 if (settee
&& !no_auth
)
1026 set_user_handle_info(settee
, hi
, 1);
1029 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1030 else if (nickserv_conf
.disable_nicks
)
1031 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1032 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1033 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1035 register_nick(user
->nick
, hi
);
1036 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1038 if (settee
&& (user
!= settee
))
1039 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1044 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1046 cookie
->hi
->cookie
= cookie
;
1047 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1050 /* Contributed by the great sneep of afternet ;) */
1051 /* Since this gets used in a URL, we want to avoid stuff that confuses
1052 * email clients such as ] and ?. a-z, 0-9 only.
1054 void genpass(char *str
, int len
)
1059 for(i
= 0; i
< len
; i
++)
1063 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1064 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1072 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1074 struct handle_cookie
*cookie
;
1075 char subject
[128], body
[4096], *misc
;
1076 const char *netname
, *fmt
;
1080 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1084 cookie
= calloc(1, sizeof(*cookie
));
1086 cookie
->type
= type
;
1087 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1089 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1090 /* Adding dedicated password gen function for more control -Rubin */
1091 genpass(cookie
->cookie
, 10);
1093 *inttobase64(cookie->cookie, rand(), 5);
1094 *inttobase64(cookie->cookie+5, rand(), 5);
1097 netname
= nickserv_conf
.network_name
;
1100 switch (cookie
->type
) {
1102 hi
->passwd
[0] = 0; /* invalidate password */
1103 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1104 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1105 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1108 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1110 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1112 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1115 case PASSWORD_CHANGE
:
1116 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1117 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1118 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1120 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1122 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1123 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1126 misc
= hi
->email_addr
;
1127 hi
->email_addr
= cookie
->data
;
1128 #ifdef stupid_verify_old_email
1130 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1131 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1132 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1133 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1134 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1135 sendmail(nickserv
, hi
, subject
, body
, 1);
1136 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1137 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1140 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1141 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1142 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1143 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1144 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1145 sendmail(nickserv
, hi
, subject
, body
, 1);
1147 #ifdef stupid_verify_old_email
1150 hi
->email_addr
= misc
;
1153 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1154 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1155 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1156 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1157 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1160 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1164 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1165 nickserv_bake_cookie(cookie
);
1169 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1171 cookie
->hi
->cookie
= NULL
;
1172 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1173 nickserv_free_cookie(cookie
);
1177 nickserv_free_email_addr(void *data
)
1179 handle_info_list_clean(data
);
1184 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1186 struct handle_info_list
*hil
;
1187 /* Remove from old handle_info_list ... */
1188 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1189 handle_info_list_remove(hil
, hi
);
1190 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1191 hi
->email_addr
= NULL
;
1193 /* Add to the new list.. */
1194 if (new_email_addr
) {
1195 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1196 hil
= calloc(1, sizeof(*hil
));
1197 hil
->tag
= strdup(new_email_addr
);
1198 handle_info_list_init(hil
);
1199 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1201 handle_info_list_append(hil
, hi
);
1202 hi
->email_addr
= hil
->tag
;
1206 static NICKSERV_FUNC(cmd_register
)
1208 struct handle_info
*hi
;
1209 const char *email_addr
, *password
;
1210 char syncpass
[MD5_CRYPT_LENGTH
];
1211 int no_auth
, weblink
;
1213 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1214 /* Require the first handle registered to belong to someone +o. */
1215 reply("NSMSG_REQUIRE_OPER");
1219 if (user
->handle_info
) {
1220 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1224 if (IsRegistering(user
)) {
1225 reply("NSMSG_ALREADY_REGISTERING");
1229 if (IsStamped(user
)) {
1230 /* Unauthenticated users might still have been stamped
1231 previously and could therefore have a hidden host;
1232 do not allow them to register a new account. */
1233 reply("NSMSG_STAMPED_REGISTER");
1237 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1239 if (!is_valid_handle(argv
[1])) {
1240 reply("NSMSG_BAD_HANDLE", argv
[1]);
1245 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1246 struct handle_info_list
*hil
;
1249 /* Remember email address. */
1250 email_addr
= argv
[3];
1252 /* Check that the email address looks valid.. */
1253 if (!is_valid_email_addr(email_addr
)) {
1254 reply("NSMSG_BAD_EMAIL_ADDR");
1258 /* .. and that we are allowed to send to it. */
1259 if ((str
= sendmail_prohibited_address(email_addr
))) {
1260 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1264 /* If we do email verify, make sure we don't spam the address. */
1265 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1267 for (nn
=0; nn
<hil
->used
; nn
++) {
1268 if (hil
->list
[nn
]->cookie
) {
1269 reply("NSMSG_EMAIL_UNACTIVATED");
1273 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1274 reply("NSMSG_EMAIL_OVERUSED");
1287 /* Webregister hack - send URL instead of IRC cookie
1290 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1294 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1296 /* Add any masks they should get. */
1297 if (nickserv_conf
.default_hostmask
) {
1298 string_list_append(hi
->masks
, strdup("*@*"));
1300 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1301 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1302 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1305 /* If they're the first to register, give them level 1000. */
1306 if (dict_size(nickserv_handle_dict
) == 1) {
1307 hi
->opserv_level
= 1000;
1308 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1311 /* Set their email address. */
1313 nickserv_set_email_addr(hi
, email_addr
);
1315 /* If they need to do email verification, tell them. */
1317 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1319 /* Set registering flag.. */
1320 user
->modes
|= FLAGS_REGISTERING
;
1322 if (nickserv_conf
.sync_log
) {
1323 cryptpass(password
, syncpass
);
1325 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1326 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1329 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1332 /* this wont work if email is required .. */
1333 process_adduser_pending(user
);
1338 static NICKSERV_FUNC(cmd_oregister
)
1341 struct userNode
*settee
;
1342 struct handle_info
*hi
;
1344 NICKSERV_MIN_PARMS(4);
1346 if (!is_valid_handle(argv
[1])) {
1347 reply("NSMSG_BAD_HANDLE", argv
[1]);
1351 if (strchr(argv
[3], '@')) {
1352 mask
= canonicalize_hostmask(strdup(argv
[3]));
1354 settee
= GetUserH(argv
[4]);
1356 reply("MSG_NICK_UNKNOWN", argv
[4]);
1363 } else if ((settee
= GetUserH(argv
[3]))) {
1364 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1366 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1369 if (settee
&& settee
->handle_info
) {
1370 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1374 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1378 string_list_append(hi
->masks
, mask
);
1382 static NICKSERV_FUNC(cmd_handleinfo
)
1385 unsigned int i
, pos
=0, herelen
;
1386 struct userNode
*target
, *next_un
;
1387 struct handle_info
*hi
;
1388 const char *nsmsg_none
;
1391 if (!(hi
= user
->handle_info
)) {
1392 reply("NSMSG_MUST_AUTH");
1395 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1399 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1400 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1402 #ifdef WITH_PROTOCOL_BAHAMUT
1403 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1405 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1408 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1409 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1411 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1414 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1415 if (HANDLE_FLAGGED(hi
, FROZEN
))
1416 reply("NSMSG_HANDLEINFO_VACATION");
1418 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1419 struct do_not_register
*dnr
;
1420 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1421 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1422 if (!oper_outranks(user
, hi
))
1424 } else if (hi
!= user
->handle_info
) {
1425 reply("NSMSG_HANDLEINFO_END");
1429 if (nickserv_conf
.email_enabled
)
1430 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1434 switch (hi
->cookie
->type
) {
1435 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1436 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1437 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1438 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1439 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1445 unsigned long flen
= 1;
1446 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1448 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1449 if (hi
->flags
& 1 << i
)
1450 flags
[flen
++] = handle_flags
[i
];
1452 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1454 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1457 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1458 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1459 || (hi
->opserv_level
> 0)) {
1460 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1464 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1466 if (hi
->last_quit_host
[0])
1467 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1469 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1471 if (nickserv_conf
.disable_nicks
) {
1472 /* nicks disabled; don't show anything about registered nicks */
1473 } else if (hi
->nicks
) {
1474 struct nick_info
*ni
, *next_ni
;
1475 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1476 herelen
= strlen(ni
->nick
);
1477 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1479 goto print_nicks_buff
;
1483 memcpy(buff
+pos
, ni
->nick
, herelen
);
1484 pos
+= herelen
; buff
[pos
++] = ' ';
1488 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1493 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1496 if (hi
->masks
->used
) {
1497 for (i
=0; i
< hi
->masks
->used
; i
++) {
1498 herelen
= strlen(hi
->masks
->list
[i
]);
1499 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1501 goto print_mask_buff
;
1503 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1504 pos
+= herelen
; buff
[pos
++] = ' ';
1505 if (i
+1 == hi
->masks
->used
) {
1508 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1513 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1517 struct userData
*channel
, *next
;
1520 for (channel
= hi
->channels
; channel
; channel
= next
) {
1521 next
= channel
->u_next
;
1522 name
= channel
->channel
->channel
->name
;
1523 herelen
= strlen(name
);
1524 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1526 goto print_chans_buff
;
1528 if (IsUserSuspended(channel
))
1530 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1534 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1539 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1542 for (target
= hi
->users
; target
; target
= next_un
) {
1543 herelen
= strlen(target
->nick
);
1544 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1546 goto print_cnick_buff
;
1548 next_un
= target
->next_authed
;
1550 memcpy(buff
+pos
, target
->nick
, herelen
);
1551 pos
+= herelen
; buff
[pos
++] = ' ';
1555 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1560 reply("NSMSG_HANDLEINFO_END");
1564 static NICKSERV_FUNC(cmd_userinfo
)
1566 struct userNode
*target
;
1568 NICKSERV_MIN_PARMS(2);
1569 if (!(target
= GetUserH(argv
[1]))) {
1570 reply("MSG_NICK_UNKNOWN", argv
[1]);
1573 if (target
->handle_info
)
1574 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1576 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1580 static NICKSERV_FUNC(cmd_nickinfo
)
1582 struct nick_info
*ni
;
1584 NICKSERV_MIN_PARMS(2);
1585 if (!(ni
= get_nick_info(argv
[1]))) {
1586 reply("MSG_NICK_UNKNOWN", argv
[1]);
1589 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1593 static NICKSERV_FUNC(cmd_rename_handle
)
1595 struct handle_info
*hi
;
1596 char msgbuf
[MAXLEN
], *old_handle
;
1599 NICKSERV_MIN_PARMS(3);
1600 if (!(hi
= get_victim_oper(user
, argv
[1])))
1602 if (!is_valid_handle(argv
[2])) {
1603 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1606 if (get_handle_info(argv
[2])) {
1607 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1610 if(strlen(argv
[2]) > 15)
1612 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1616 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1617 hi
->handle
= strdup(argv
[2]);
1618 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1619 for (nn
=0; nn
<rf_list_used
; nn
++)
1620 rf_list
[nn
](hi
, old_handle
);
1621 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1622 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1623 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1628 static failpw_func_t
*failpw_func_list
;
1629 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1632 reg_failpw_func(failpw_func_t func
)
1634 if (failpw_func_used
== failpw_func_size
) {
1635 if (failpw_func_size
) {
1636 failpw_func_size
<<= 1;
1637 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1639 failpw_func_size
= 8;
1640 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1643 failpw_func_list
[failpw_func_used
++] = func
;
1647 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1649 * called by nefariouses enhanced AC login-on-connect code
1652 struct handle_info
*loc_auth(char *handle
, char *password
)
1654 int pw_arg
, used
, maxlogins
;
1657 struct handle_info
*hi
;
1658 struct userNode
*other
;
1660 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1666 /* We don't know the users hostname, or anything because they
1667 * havn't registered yet. So we can only allow LOC if your
1668 * account has *@* as a hostmask.
1670 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1672 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1681 /* Responses from here on look up the language used by the handle they asked about. */
1682 if (!checkpass(password
, hi
->passwd
)) {
1685 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1688 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1689 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1690 if (++used
>= maxlogins
) {
1697 static NICKSERV_FUNC(cmd_auth
)
1699 int pw_arg
, used
, maxlogins
;
1700 struct handle_info
*hi
;
1702 struct userNode
*other
;
1704 if (user
->handle_info
) {
1705 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1708 if (IsStamped(user
)) {
1709 /* Unauthenticated users might still have been stamped
1710 previously and could therefore have a hidden host;
1711 do not allow them to authenticate. */
1712 reply("NSMSG_STAMPED_AUTH");
1716 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1718 } else if (argc
== 2) {
1719 if (nickserv_conf
.disable_nicks
) {
1720 if (!(hi
= get_handle_info(user
->nick
))) {
1721 reply("NSMSG_HANDLE_NOT_FOUND");
1725 /* try to look up their handle from their nick */
1726 struct nick_info
*ni
;
1727 ni
= get_nick_info(user
->nick
);
1729 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1736 reply("MSG_MISSING_PARAMS", argv
[0]);
1737 svccmd_send_help_brief(user
, nickserv
, cmd
);
1741 reply("NSMSG_HANDLE_NOT_FOUND");
1744 /* Responses from here on look up the language used by the handle they asked about. */
1745 passwd
= argv
[pw_arg
];
1746 if (!valid_user_for(user
, hi
)) {
1747 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1748 send_message_type(4, user
, cmd
->parent
->bot
,
1749 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1752 send_message_type(4, user
, cmd
->parent
->bot
,
1753 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1755 argv
[pw_arg
] = "BADMASK";
1758 if (!checkpass(passwd
, hi
->passwd
)) {
1760 send_message_type(4, user
, cmd
->parent
->bot
,
1761 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1762 argv
[pw_arg
] = "BADPASS";
1763 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1764 if (nickserv_conf
.autogag_enabled
) {
1765 if (!user
->auth_policer
.params
) {
1766 user
->auth_policer
.last_req
= now
;
1767 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1769 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1771 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1772 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1773 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1775 argv
[pw_arg
] = "GAGGED";
1780 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1781 send_message_type(4, user
, cmd
->parent
->bot
,
1782 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1783 argv
[pw_arg
] = "SUSPENDED";
1786 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1787 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1788 if (++used
>= maxlogins
) {
1789 send_message_type(4, user
, cmd
->parent
->bot
,
1790 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1792 argv
[pw_arg
] = "MAXLOGINS";
1797 set_user_handle_info(user
, hi
, 1);
1798 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1799 reply("NSMSG_PLEASE_SET_EMAIL");
1800 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1801 reply("NSMSG_WEAK_PASSWORD");
1802 if (hi
->passwd
[0] != '$')
1803 cryptpass(passwd
, hi
->passwd
);
1805 /* If a channel was waiting for this user to auth,
1806 * finish adding them */
1807 process_adduser_pending(user
);
1809 reply("NSMSG_AUTH_SUCCESS");
1813 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
1814 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
1816 irc_umode(user
,nickserv_conf
.auto_admin
);
1817 reply("NSMSG_AUTO_OPER_ADMIN");
1819 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
1821 irc_umode(user
,nickserv_conf
.auto_oper
);
1822 reply("NSMSG_AUTO_OPER");
1826 /* Wipe out the pass for the logs */
1827 argv
[pw_arg
] = "****";
1831 static allowauth_func_t
*allowauth_func_list
;
1832 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1835 reg_allowauth_func(allowauth_func_t func
)
1837 if (allowauth_func_used
== allowauth_func_size
) {
1838 if (allowauth_func_size
) {
1839 allowauth_func_size
<<= 1;
1840 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1842 allowauth_func_size
= 8;
1843 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1846 allowauth_func_list
[allowauth_func_used
++] = func
;
1849 static NICKSERV_FUNC(cmd_allowauth
)
1851 struct userNode
*target
;
1852 struct handle_info
*hi
;
1855 NICKSERV_MIN_PARMS(2);
1856 if (!(target
= GetUserH(argv
[1]))) {
1857 reply("MSG_NICK_UNKNOWN", argv
[1]);
1860 if (target
->handle_info
) {
1861 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1864 if (IsStamped(target
)) {
1865 /* Unauthenticated users might still have been stamped
1866 previously and could therefore have a hidden host;
1867 do not allow them to authenticate to an account. */
1868 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1873 else if (!(hi
= get_handle_info(argv
[2]))) {
1874 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1878 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1879 reply("MSG_USER_OUTRANKED", hi
->handle
);
1882 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1883 || (hi
->opserv_level
> 0))
1884 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1885 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1888 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1889 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1890 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1891 if (nickserv_conf
.email_enabled
)
1892 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1894 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1895 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1897 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1899 for (n
=0; n
<allowauth_func_used
; n
++)
1900 allowauth_func_list
[n
](user
, target
, hi
);
1904 static NICKSERV_FUNC(cmd_authcookie
)
1906 struct handle_info
*hi
;
1908 NICKSERV_MIN_PARMS(2);
1909 if (user
->handle_info
) {
1910 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1913 if (IsStamped(user
)) {
1914 /* Unauthenticated users might still have been stamped
1915 previously and could therefore have a hidden host;
1916 do not allow them to authenticate to an account. */
1917 reply("NSMSG_STAMPED_AUTHCOOKIE");
1920 if (!(hi
= get_handle_info(argv
[1]))) {
1921 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1924 if (!hi
->email_addr
) {
1925 reply("MSG_SET_EMAIL_ADDR");
1928 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1932 static NICKSERV_FUNC(cmd_delcookie
)
1934 struct handle_info
*hi
;
1936 hi
= user
->handle_info
;
1938 reply("NSMSG_NO_COOKIE");
1941 switch (hi
->cookie
->type
) {
1944 reply("NSMSG_MUST_TIME_OUT");
1947 nickserv_eat_cookie(hi
->cookie
);
1948 reply("NSMSG_ATE_COOKIE");
1954 static NICKSERV_FUNC(cmd_odelcookie
)
1956 struct handle_info
*hi
;
1958 NICKSERV_MIN_PARMS(2);
1960 if (!(hi
= get_victim_oper(user
, argv
[1])))
1964 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
1968 nickserv_eat_cookie(hi
->cookie
);
1969 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
1974 static NICKSERV_FUNC(cmd_resetpass
)
1976 struct handle_info
*hi
;
1977 char crypted
[MD5_CRYPT_LENGTH
];
1980 NICKSERV_MIN_PARMS(3);
1981 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
1985 if (user
->handle_info
) {
1986 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1989 if (IsStamped(user
)) {
1990 /* Unauthenticated users might still have been stamped
1991 previously and could therefore have a hidden host;
1992 do not allow them to activate an account. */
1993 reply("NSMSG_STAMPED_RESETPASS");
1996 if (!(hi
= get_handle_info(argv
[1]))) {
1997 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2000 if (!hi
->email_addr
) {
2001 reply("MSG_SET_EMAIL_ADDR");
2004 cryptpass(argv
[2], crypted
);
2006 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2010 static NICKSERV_FUNC(cmd_cookie
)
2012 struct handle_info
*hi
;
2015 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2018 NICKSERV_MIN_PARMS(3);
2019 if (!(hi
= get_handle_info(argv
[1]))) {
2020 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2026 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2027 reply("NSMSG_HANDLE_SUSPENDED");
2032 reply("NSMSG_NO_COOKIE");
2036 /* Check validity of operation before comparing cookie to
2037 * prohibit guessing by authed users. */
2038 if (user
->handle_info
2039 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2040 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2041 reply("NSMSG_CANNOT_COOKIE");
2045 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2046 reply("NSMSG_BAD_COOKIE");
2050 switch (hi
->cookie
->type
) {
2052 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2053 set_user_handle_info(user
, hi
, 1);
2054 reply("NSMSG_HANDLE_ACTIVATED");
2055 if (nickserv_conf
.sync_log
)
2056 SyncLog("ACCOUNTACC %s", hi
->handle
);
2058 case PASSWORD_CHANGE
:
2059 set_user_handle_info(user
, hi
, 1);
2060 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2061 reply("NSMSG_PASSWORD_CHANGED");
2062 if (nickserv_conf
.sync_log
)
2063 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2066 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2068 * This should only happen if an OREGISTER was sent. Require
2069 * email must be enabled! - SiRVulcaN
2071 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2073 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2074 reply("NSMSG_EMAIL_CHANGED");
2075 if (nickserv_conf
.sync_log
)
2076 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2079 set_user_handle_info(user
, hi
, 1);
2080 reply("NSMSG_AUTH_SUCCESS");
2083 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2084 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2088 nickserv_eat_cookie(hi
->cookie
);
2090 process_adduser_pending(user
);
2095 static NICKSERV_FUNC(cmd_oregnick
) {
2097 struct handle_info
*target
;
2098 struct nick_info
*ni
;
2100 NICKSERV_MIN_PARMS(3);
2101 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2104 if (!is_registerable_nick(nick
)) {
2105 reply("NSMSG_BAD_NICK", nick
);
2108 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2110 reply("NSMSG_NICK_EXISTS", nick
);
2113 register_nick(nick
, target
);
2114 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2118 static NICKSERV_FUNC(cmd_regnick
) {
2120 struct nick_info
*ni
;
2122 if (!is_registerable_nick(user
->nick
)) {
2123 reply("NSMSG_BAD_NICK", user
->nick
);
2126 /* count their nicks, see if it's too many */
2127 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2128 if (n
>= nickserv_conf
.nicks_per_handle
) {
2129 reply("NSMSG_TOO_MANY_NICKS");
2132 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2134 reply("NSMSG_NICK_EXISTS", user
->nick
);
2137 register_nick(user
->nick
, user
->handle_info
);
2138 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2142 static NICKSERV_FUNC(cmd_pass
)
2144 struct handle_info
*hi
;
2145 const char *old_pass
, *new_pass
;
2147 NICKSERV_MIN_PARMS(3);
2148 hi
= user
->handle_info
;
2152 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2153 if (!checkpass(old_pass
, hi
->passwd
)) {
2154 argv
[1] = "BADPASS";
2155 reply("NSMSG_PASSWORD_INVALID");
2158 cryptpass(new_pass
, hi
->passwd
);
2159 if (nickserv_conf
.sync_log
)
2160 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2162 reply("NSMSG_PASS_SUCCESS");
2167 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2170 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2171 for (i
=0; i
<hi
->masks
->used
; i
++) {
2172 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2173 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2178 string_list_append(hi
->masks
, new_mask
);
2179 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2183 static NICKSERV_FUNC(cmd_addmask
)
2186 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2187 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2191 if (!is_gline(argv
[1])) {
2192 reply("NSMSG_MASK_INVALID", argv
[1]);
2195 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2199 static NICKSERV_FUNC(cmd_oaddmask
)
2201 struct handle_info
*hi
;
2203 NICKSERV_MIN_PARMS(3);
2204 if (!(hi
= get_victim_oper(user
, argv
[1])))
2206 return nickserv_addmask(user
, hi
, argv
[2]);
2210 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2213 for (i
=0; i
<hi
->masks
->used
; i
++) {
2214 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2215 char *old_mask
= hi
->masks
->list
[i
];
2216 if (hi
->masks
->used
== 1) {
2217 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2220 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2221 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2226 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2230 static NICKSERV_FUNC(cmd_delmask
)
2232 NICKSERV_MIN_PARMS(2);
2233 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2236 static NICKSERV_FUNC(cmd_odelmask
)
2238 struct handle_info
*hi
;
2239 NICKSERV_MIN_PARMS(3);
2240 if (!(hi
= get_victim_oper(user
, argv
[1])))
2242 return nickserv_delmask(user
, hi
, argv
[2]);
2246 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2247 unsigned int nn
, add
= 1, pos
;
2248 unsigned long added
, removed
, flag
;
2250 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2252 case '+': add
= 1; break;
2253 case '-': add
= 0; break;
2255 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2256 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2259 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2260 /* cheesy avoidance of looking up the flag name.. */
2261 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2264 flag
= 1 << (pos
- 1);
2266 added
|= flag
, removed
&= ~flag
;
2268 removed
|= flag
, added
&= ~flag
;
2273 *premoved
= removed
;
2278 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2280 unsigned long before
, after
, added
, removed
;
2281 struct userNode
*uNode
;
2283 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2284 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2286 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2287 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2289 /* Strip helping flag if they're only a support helper and not
2290 * currently in #support. */
2291 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2292 struct channelList
*schannels
;
2294 schannels
= chanserv_support_channels();
2295 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2296 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2297 if (GetUserMode(schannels
->list
[ii
], uNode
))
2299 if (ii
< schannels
->used
)
2303 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2306 if (after
&& !before
) {
2307 /* Add user to current helper list. */
2308 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2309 userList_append(&curr_helpers
, uNode
);
2310 } else if (!after
&& before
) {
2311 /* Remove user from current helper list. */
2312 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2313 userList_remove(&curr_helpers
, uNode
);
2320 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2324 char *set_display
[] = {
2325 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", /* "STYLE", */
2326 "EMAIL", "ANNOUNCEMENTS", "MAXLOGINS", "LANGUAGE",
2327 "FAKEHOST", "TITLE", "EPITHET"
2330 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2331 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2333 /* Do this so options are presented in a consistent order. */
2334 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2335 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2336 opt(user
, hi
, override
, 0, NULL
);
2337 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2340 static NICKSERV_FUNC(cmd_set
)
2342 struct handle_info
*hi
;
2345 hi
= user
->handle_info
;
2347 set_list(user
, hi
, 0);
2350 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2351 reply("NSMSG_INVALID_OPTION", argv
[1]);
2354 return opt(user
, hi
, 0, argc
-1, argv
+1);
2357 static NICKSERV_FUNC(cmd_oset
)
2359 struct handle_info
*hi
;
2362 NICKSERV_MIN_PARMS(2);
2364 if (!(hi
= get_victim_oper(user
, argv
[1])))
2368 set_list(user
, hi
, 0);
2372 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2373 reply("NSMSG_INVALID_OPTION", argv
[2]);
2377 return opt(user
, hi
, 1, argc
-2, argv
+2);
2380 static OPTION_FUNC(opt_info
)
2384 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2386 hi
->infoline
= NULL
;
2388 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2392 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2393 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2397 static OPTION_FUNC(opt_width
)
2400 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2402 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2403 hi
->screen_width
= MIN_LINE_SIZE
;
2404 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2405 hi
->screen_width
= MAX_LINE_SIZE
;
2407 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2411 static OPTION_FUNC(opt_tablewidth
)
2414 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2416 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2417 hi
->table_width
= MIN_LINE_SIZE
;
2418 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2419 hi
->table_width
= MAX_LINE_SIZE
;
2421 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2425 static OPTION_FUNC(opt_color
)
2428 if (enabled_string(argv
[1]))
2429 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2430 else if (disabled_string(argv
[1]))
2431 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2433 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2438 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2442 static OPTION_FUNC(opt_privmsg
)
2445 if (enabled_string(argv
[1]))
2446 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2447 else if (disabled_string(argv
[1]))
2448 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2450 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2455 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2460 static OPTION_FUNC(opt_style)
2465 if (!irccasecmp(argv[1], "Zoot"))
2466 hi->userlist_style = HI_STYLE_ZOOT;
2467 else if (!irccasecmp(argv[1], "def"))
2468 hi->userlist_style = HI_STYLE_DEF;
2471 switch (hi->userlist_style) {
2480 send_message(user, nickserv, "NSMSG_SET_STYLE", style);
2485 static OPTION_FUNC(opt_announcements
)
2490 if (enabled_string(argv
[1]))
2491 hi
->announcements
= 'y';
2492 else if (disabled_string(argv
[1]))
2493 hi
->announcements
= 'n';
2494 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2495 hi
->announcements
= '?';
2497 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2502 switch (hi
->announcements
) {
2503 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2504 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2505 case '?': choice
= "default"; break;
2506 default: choice
= "unknown"; break;
2508 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2512 static OPTION_FUNC(opt_password
)
2515 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2520 cryptpass(argv
[1], hi
->passwd
);
2522 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2526 static OPTION_FUNC(opt_flags
)
2529 unsigned int ii
, flen
;
2532 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2537 nickserv_apply_flags(user
, hi
, argv
[1]);
2539 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2540 if (hi
->flags
& (1 << ii
))
2541 flags
[flen
++] = handle_flags
[ii
];
2544 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2546 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2550 static OPTION_FUNC(opt_email
)
2554 if (!is_valid_email_addr(argv
[1])) {
2555 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2558 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2559 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2562 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2563 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2565 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2567 nickserv_set_email_addr(hi
, argv
[1]);
2569 nickserv_eat_cookie(hi
->cookie
);
2570 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2573 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2577 static OPTION_FUNC(opt_maxlogins
)
2579 unsigned char maxlogins
;
2581 maxlogins
= strtoul(argv
[1], NULL
, 0);
2582 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2583 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2586 hi
->maxlogins
= maxlogins
;
2588 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2589 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2593 static OPTION_FUNC(opt_language
)
2595 struct language
*lang
;
2597 lang
= language_find(argv
[1]);
2598 if (irccasecmp(lang
->name
, argv
[1]))
2599 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2600 hi
->language
= lang
;
2602 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2607 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2608 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2610 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2611 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2612 && (user
->handle_info
->opserv_level
< 1000))) {
2613 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2616 if ((user
->handle_info
->opserv_level
< new_level
)
2617 || ((user
->handle_info
->opserv_level
== new_level
)
2618 && (user
->handle_info
->opserv_level
< 1000))) {
2619 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2622 if (user
->handle_info
== target
) {
2623 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2626 if (target
->opserv_level
== new_level
)
2628 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2629 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2630 target
->opserv_level
= new_level
;
2634 static OPTION_FUNC(opt_level
)
2639 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2643 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2644 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2648 static OPTION_FUNC(opt_epithet
)
2650 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2653 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2657 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2661 if ((epithet
[0] == '*') && !epithet
[1])
2664 hi
->epithet
= strdup(epithet
);
2668 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2670 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2674 static OPTION_FUNC(opt_title
)
2678 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2680 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2685 if (strchr(title
, '.')) {
2686 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2689 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2690 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2691 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2696 if (!strcmp(title
, "*")) {
2697 hi
->fakehost
= NULL
;
2699 hi
->fakehost
= malloc(strlen(title
)+2);
2700 hi
->fakehost
[0] = '.';
2701 strcpy(hi
->fakehost
+1, title
);
2704 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2705 title
= hi
->fakehost
+ 1;
2709 title
= user_find_message(user
, "MSG_NONE");
2710 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2714 static OPTION_FUNC(opt_fakehost
)
2718 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2720 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2725 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2726 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2730 if (!strcmp(fake
, "*"))
2731 hi
->fakehost
= NULL
;
2733 hi
->fakehost
= strdup(fake
);
2734 fake
= hi
->fakehost
;
2737 fake
= generate_fakehost(hi
);
2739 fake
= user_find_message(user
, "MSG_NONE");
2740 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2744 static NICKSERV_FUNC(cmd_reclaim
)
2746 struct handle_info
*hi
;
2747 struct nick_info
*ni
;
2748 struct userNode
*victim
;
2750 NICKSERV_MIN_PARMS(2);
2751 hi
= user
->handle_info
;
2752 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2754 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2757 if (ni
->owner
!= user
->handle_info
) {
2758 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2761 victim
= GetUserH(ni
->nick
);
2763 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2766 if (victim
== user
) {
2767 reply("NSMSG_NICK_USER_YOU");
2770 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2771 switch (nickserv_conf
.reclaim_action
) {
2772 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2773 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2774 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2775 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2780 static NICKSERV_FUNC(cmd_unregnick
)
2783 struct handle_info
*hi
;
2784 struct nick_info
*ni
;
2786 hi
= user
->handle_info
;
2787 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2788 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2790 reply("NSMSG_UNKNOWN_NICK", nick
);
2793 if (hi
!= ni
->owner
) {
2794 reply("NSMSG_NOT_YOUR_NICK", nick
);
2797 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2802 static NICKSERV_FUNC(cmd_ounregnick
)
2804 struct nick_info
*ni
;
2806 NICKSERV_MIN_PARMS(2);
2807 if (!(ni
= get_nick_info(argv
[1]))) {
2808 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2811 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2812 reply("MSG_USER_OUTRANKED", ni
->nick
);
2815 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2820 static NICKSERV_FUNC(cmd_unregister
)
2822 struct handle_info
*hi
;
2825 NICKSERV_MIN_PARMS(2);
2826 hi
= user
->handle_info
;
2829 if (checkpass(passwd
, hi
->passwd
)) {
2830 nickserv_unregister_handle(hi
, user
);
2833 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2834 reply("NSMSG_PASSWORD_INVALID");
2839 static NICKSERV_FUNC(cmd_ounregister
)
2841 struct handle_info
*hi
;
2843 NICKSERV_MIN_PARMS(2);
2844 if (!(hi
= get_victim_oper(user
, argv
[1])))
2846 nickserv_unregister_handle(hi
, user
);
2850 static NICKSERV_FUNC(cmd_status
)
2852 if (nickserv_conf
.disable_nicks
) {
2853 reply("NSMSG_GLOBAL_STATS_NONICK",
2854 dict_size(nickserv_handle_dict
));
2856 if (user
->handle_info
) {
2858 struct nick_info
*ni
;
2859 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2860 reply("NSMSG_HANDLE_STATS", cnt
);
2862 reply("NSMSG_HANDLE_NONE");
2864 reply("NSMSG_GLOBAL_STATS",
2865 dict_size(nickserv_handle_dict
),
2866 dict_size(nickserv_nick_dict
));
2871 static NICKSERV_FUNC(cmd_ghost
)
2873 struct userNode
*target
;
2874 char reason
[MAXLEN
];
2876 NICKSERV_MIN_PARMS(2);
2877 if (!(target
= GetUserH(argv
[1]))) {
2878 reply("MSG_NICK_UNKNOWN", argv
[1]);
2881 if (target
== user
) {
2882 reply("NSMSG_CANNOT_GHOST_SELF");
2885 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2886 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2889 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2890 DelUser(target
, nickserv
, 1, reason
);
2891 reply("NSMSG_GHOST_KILLED", argv
[1]);
2895 static NICKSERV_FUNC(cmd_vacation
)
2897 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2898 reply("NSMSG_ON_VACATION");
2903 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2905 struct handle_info
*hi
;
2908 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2910 #ifdef WITH_PROTOCOL_BAHAMUT
2913 saxdb_start_record(ctx
, iter_key(it
), 0);
2914 if (hi
->announcements
!= '?') {
2915 flags
[0] = hi
->announcements
;
2917 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2920 struct handle_cookie
*cookie
= hi
->cookie
;
2923 switch (cookie
->type
) {
2924 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2925 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2926 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2927 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2928 default: type
= NULL
; break;
2931 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2932 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2933 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2935 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2936 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2937 saxdb_end_record(ctx
);
2941 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
2943 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
2945 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
2949 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
2950 if (hi
->flags
& (1 << ii
))
2951 flags
[flen
++] = handle_flags
[ii
];
2953 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
2955 #ifdef WITH_PROTOCOL_BAHAMUT
2956 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
2959 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
2960 if (hi
->last_quit_host
[0])
2961 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
2962 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
2963 if (hi
->masks
->used
)
2964 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
2966 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
2968 struct string_list
*slist
;
2969 struct nick_info
*ni
;
2971 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
2972 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
2973 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
2977 if (hi
->opserv_level
)
2978 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
2979 if (hi
->language
!= lang_C
)
2980 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
2981 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
2982 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
2983 if (hi
->screen_width
)
2984 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
2985 if (hi
->table_width
)
2986 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
2987 flags
[0] = hi
->userlist_style
;
2989 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
2990 saxdb_end_record(ctx
);
2995 static handle_merge_func_t
*handle_merge_func_list
;
2996 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
2999 reg_handle_merge_func(handle_merge_func_t func
)
3001 if (handle_merge_func_used
== handle_merge_func_size
) {
3002 if (handle_merge_func_size
) {
3003 handle_merge_func_size
<<= 1;
3004 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3006 handle_merge_func_size
= 8;
3007 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3010 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3013 static NICKSERV_FUNC(cmd_merge
)
3015 struct handle_info
*hi_from
, *hi_to
;
3016 struct userNode
*last_user
;
3017 struct userData
*cList
, *cListNext
;
3018 unsigned int ii
, jj
, n
;
3019 char buffer
[MAXLEN
];
3021 NICKSERV_MIN_PARMS(3);
3023 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3025 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3027 if (hi_to
== hi_from
) {
3028 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3032 for (n
=0; n
<handle_merge_func_used
; n
++)
3033 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3035 /* Append "from" handle's nicks to "to" handle's nick list. */
3037 struct nick_info
*last_ni
;
3038 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3039 last_ni
->next
= hi_from
->nicks
;
3041 while (hi_from
->nicks
) {
3042 hi_from
->nicks
->owner
= hi_to
;
3043 hi_from
->nicks
= hi_from
->nicks
->next
;
3046 /* Merge the hostmasks. */
3047 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3048 char *mask
= hi_from
->masks
->list
[ii
];
3049 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3050 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3052 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3053 string_list_append(hi_to
->masks
, strdup(mask
));
3056 /* Merge the lists of authed users. */
3058 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3059 last_user
->next_authed
= hi_from
->users
;
3061 hi_to
->users
= hi_from
->users
;
3063 /* Repoint the old "from" handle's users. */
3064 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3065 last_user
->handle_info
= hi_to
;
3067 hi_from
->users
= NULL
;
3069 /* Merge channel userlists. */
3070 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3071 struct userData
*cList2
;
3072 cListNext
= cList
->u_next
;
3073 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3074 if (cList
->channel
== cList2
->channel
)
3076 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3077 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
);
3078 /* keep cList2 in hi_to; remove cList from hi_from */
3079 del_channel_user(cList
, 1);
3082 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
);
3083 /* remove the lower-ranking cList2 from hi_to */
3084 del_channel_user(cList2
, 1);
3086 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3088 /* cList needs to be moved from hi_from to hi_to */
3089 cList
->handle
= hi_to
;
3090 /* Remove from linked list for hi_from */
3091 assert(!cList
->u_prev
);
3092 hi_from
->channels
= cList
->u_next
;
3094 cList
->u_next
->u_prev
= cList
->u_prev
;
3095 /* Add to linked list for hi_to */
3096 cList
->u_prev
= NULL
;
3097 cList
->u_next
= hi_to
->channels
;
3098 if (hi_to
->channels
)
3099 hi_to
->channels
->u_prev
= cList
;
3100 hi_to
->channels
= cList
;
3104 /* Do they get an OpServ level promotion? */
3105 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3106 hi_to
->opserv_level
= hi_from
->opserv_level
;
3108 /* What about last seen time? */
3109 if (hi_from
->lastseen
> hi_to
->lastseen
)
3110 hi_to
->lastseen
= hi_from
->lastseen
;
3112 /* Does a fakehost carry over? (This intentionally doesn't set it
3113 * for users previously attached to hi_to. They'll just have to
3116 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3117 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3119 /* Notify of success. */
3120 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3121 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3122 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3124 /* Unregister the "from" handle. */
3125 nickserv_unregister_handle(hi_from
, NULL
);
3130 struct nickserv_discrim
{
3131 unsigned int limit
, min_level
, max_level
;
3132 unsigned long flags_on
, flags_off
;
3133 time_t min_registered
, max_registered
;
3135 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3136 const char *nickmask
;
3137 const char *hostmask
;
3138 const char *handlemask
;
3139 const char *emailmask
;
3142 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3144 struct discrim_apply_info
{
3145 struct nickserv_discrim
*discrim
;
3146 discrim_search_func func
;
3147 struct userNode
*source
;
3148 unsigned int matched
;
3151 static struct nickserv_discrim
*
3152 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3155 struct nickserv_discrim
*discrim
;
3157 discrim
= malloc(sizeof(*discrim
));
3158 memset(discrim
, 0, sizeof(*discrim
));
3159 discrim
->min_level
= 0;
3160 discrim
->max_level
= ~0;
3161 discrim
->limit
= 50;
3162 discrim
->min_registered
= 0;
3163 discrim
->max_registered
= INT_MAX
;
3164 discrim
->lastseen
= now
;
3166 for (i
=0; i
<argc
; i
++) {
3167 if (i
== argc
- 1) {
3168 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3171 if (!irccasecmp(argv
[i
], "limit")) {
3172 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3173 } else if (!irccasecmp(argv
[i
], "flags")) {
3174 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3175 } else if (!irccasecmp(argv
[i
], "registered")) {
3176 const char *cmp
= argv
[++i
];
3177 if (cmp
[0] == '<') {
3178 if (cmp
[1] == '=') {
3179 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3181 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3183 } else if (cmp
[0] == '=') {
3184 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3185 } else if (cmp
[0] == '>') {
3186 if (cmp
[1] == '=') {
3187 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3189 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3192 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3194 } else if (!irccasecmp(argv
[i
], "seen")) {
3195 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3196 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3197 discrim
->nickmask
= argv
[++i
];
3198 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3200 if (!irccasecmp(argv
[i
], "exact")) {
3201 if (i
== argc
- 1) {
3202 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3205 discrim
->hostmask_type
= EXACT
;
3206 } else if (!irccasecmp(argv
[i
], "subset")) {
3207 if (i
== argc
- 1) {
3208 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3211 discrim
->hostmask_type
= SUBSET
;
3212 } else if (!irccasecmp(argv
[i
], "superset")) {
3213 if (i
== argc
- 1) {
3214 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3217 discrim
->hostmask_type
= SUPERSET
;
3218 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3219 if (i
== argc
- 1) {
3220 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3223 discrim
->hostmask_type
= LASTQUIT
;
3226 discrim
->hostmask_type
= SUPERSET
;
3228 discrim
->hostmask
= argv
[++i
];
3229 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3230 if (!irccasecmp(argv
[++i
], "*")) {
3231 discrim
->handlemask
= 0;
3233 discrim
->handlemask
= argv
[i
];
3235 } else if (!irccasecmp(argv
[i
], "email")) {
3236 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3237 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3239 } else if (!irccasecmp(argv
[++i
], "*")) {
3240 discrim
->emailmask
= 0;
3242 discrim
->emailmask
= argv
[i
];
3244 } else if (!irccasecmp(argv
[i
], "access")) {
3245 const char *cmp
= argv
[++i
];
3246 if (cmp
[0] == '<') {
3247 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3248 if (cmp
[1] == '=') {
3249 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3251 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3253 } else if (cmp
[0] == '=') {
3254 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3255 } else if (cmp
[0] == '>') {
3256 if (cmp
[1] == '=') {
3257 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3259 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3262 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3265 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3276 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3278 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3279 || (discrim
->flags_off
& hi
->flags
)
3280 || (discrim
->min_registered
> hi
->registered
)
3281 || (discrim
->max_registered
< hi
->registered
)
3282 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3283 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3284 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3285 || (discrim
->min_level
> hi
->opserv_level
)
3286 || (discrim
->max_level
< hi
->opserv_level
)) {
3289 if (discrim
->hostmask
) {
3291 for (i
=0; i
<hi
->masks
->used
; i
++) {
3292 const char *mask
= hi
->masks
->list
[i
];
3293 if ((discrim
->hostmask_type
== SUBSET
)
3294 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3295 else if ((discrim
->hostmask_type
== EXACT
)
3296 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3297 else if ((discrim
->hostmask_type
== SUPERSET
)
3298 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3299 else if ((discrim
->hostmask_type
== LASTQUIT
)
3300 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3302 if (i
==hi
->masks
->used
) return 0;
3304 if (discrim
->nickmask
) {
3305 struct nick_info
*nick
= hi
->nicks
;
3307 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3310 if (!nick
) return 0;
3316 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3318 dict_iterator_t it
, next
;
3319 unsigned int matched
;
3321 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3322 it
&& (matched
< discrim
->limit
);
3324 next
= iter_next(it
);
3325 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3326 dsf(source
, iter_data(it
));
3334 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3336 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3340 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3345 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3347 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3348 nickserv_unregister_handle(match
, source
);
3352 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3354 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3355 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3356 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3357 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3358 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3362 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3364 struct handle_info_list hil
;
3365 struct helpfile_table tbl
;
3370 memset(&hil
, 0, sizeof(hil
));
3371 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3372 struct handle_info
*hi
= iter_data(it
);
3373 if (hi
->opserv_level
)
3374 handle_info_list_append(&hil
, hi
);
3376 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3377 tbl
.length
= hil
.used
+ 1;
3379 tbl
.flags
= TABLE_NO_FREE
;
3380 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3381 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3384 for (ii
= 0; ii
< hil
.used
; ) {
3385 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3386 ary
[0] = hil
.list
[ii
]->handle
;
3387 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3388 tbl
.contents
[++ii
] = ary
;
3390 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3391 reply("MSG_MATCH_COUNT", hil
.used
);
3392 for (ii
= 0; ii
< hil
.used
; ii
++)
3393 free(tbl
.contents
[ii
]);
3398 static NICKSERV_FUNC(cmd_search
)
3400 struct nickserv_discrim
*discrim
;
3401 discrim_search_func action
;
3402 struct svccmd
*subcmd
;
3403 unsigned int matches
;
3406 NICKSERV_MIN_PARMS(3);
3407 sprintf(buf
, "search %s", argv
[1]);
3408 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3409 if (!irccasecmp(argv
[1], "print"))
3410 action
= search_print_func
;
3411 else if (!irccasecmp(argv
[1], "count"))
3412 action
= search_count_func
;
3413 else if (!irccasecmp(argv
[1], "unregister"))
3414 action
= search_unregister_func
;
3416 reply("NSMSG_INVALID_ACTION", argv
[1]);
3420 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3423 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3427 if (action
== search_print_func
)
3428 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3429 else if (action
== search_count_func
)
3430 discrim
->limit
= INT_MAX
;
3432 matches
= nickserv_discrim_search(discrim
, action
, user
);
3435 reply("MSG_MATCH_COUNT", matches
);
3437 reply("MSG_NO_MATCHES");
3443 static MODCMD_FUNC(cmd_checkpass
)
3445 struct handle_info
*hi
;
3447 NICKSERV_MIN_PARMS(3);
3448 if (!(hi
= get_handle_info(argv
[1]))) {
3449 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3452 if (checkpass(argv
[2], hi
->passwd
))
3453 reply("CHECKPASS_YES");
3455 reply("CHECKPASS_NO");
3461 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3464 struct string_list
*masks
, *slist
;
3465 struct handle_info
*hi
;
3466 struct userNode
*authed_users
;
3467 struct userData
*channels
;
3468 unsigned long int id
;
3472 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3473 id
= str
? strtoul(str
, NULL
, 0) : 0;
3474 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3476 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3479 if ((hi
= get_handle_info(handle
))) {
3480 authed_users
= hi
->users
;
3481 channels
= hi
->channels
;
3483 hi
->channels
= NULL
;
3484 dict_remove(nickserv_handle_dict
, hi
->handle
);
3486 authed_users
= NULL
;
3489 hi
= register_handle(handle
, str
, id
);
3491 hi
->users
= authed_users
;
3492 while (authed_users
) {
3493 authed_users
->handle_info
= hi
;
3494 authed_users
= authed_users
->next_authed
;
3497 hi
->channels
= channels
;
3498 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3499 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3500 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3501 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3502 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3503 hi
->language
= language_find(str
? str
: "C");
3504 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3505 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3506 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3508 hi
->infoline
= strdup(str
);
3509 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3510 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3511 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3512 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3513 /* We want to read the nicks even if disable_nicks is set. This is so
3514 * that we don't lose the nick data entirely. */
3515 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3517 for (ii
=0; ii
<slist
->used
; ii
++)
3518 register_nick(slist
->list
[ii
], hi
);
3520 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3522 for (ii
=0; str
[ii
]; ii
++)
3523 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3525 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3526 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3527 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3528 hi
->announcements
= str
? str
[0] : '?';
3529 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3530 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3531 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3532 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3533 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3535 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3537 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3538 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3540 nickserv_set_email_addr(hi
, str
);
3541 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3543 hi
->epithet
= strdup(str
);
3544 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3546 hi
->fakehost
= strdup(str
);
3547 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3549 const char *data
, *type
, *expires
, *cookie_str
;
3550 struct handle_cookie
*cookie
;
3552 cookie
= calloc(1, sizeof(*cookie
));
3553 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3554 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3555 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3556 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3557 if (!type
|| !expires
|| !cookie_str
) {
3558 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3561 if (!irccasecmp(type
, KEY_ACTIVATION
))
3562 cookie
->type
= ACTIVATION
;
3563 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3564 cookie
->type
= PASSWORD_CHANGE
;
3565 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3566 cookie
->type
= EMAIL_CHANGE
;
3567 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3568 cookie
->type
= ALLOWAUTH
;
3570 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3573 cookie
->expires
= strtoul(expires
, NULL
, 0);
3574 if (cookie
->expires
< now
)
3577 cookie
->data
= strdup(data
);
3578 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3582 nickserv_bake_cookie(cookie
);
3584 nickserv_free_cookie(cookie
);
3589 nickserv_saxdb_read(dict_t db
) {
3591 struct record_data
*rd
;
3593 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3595 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3600 static NICKSERV_FUNC(cmd_mergedb
)
3602 struct timeval start
, stop
;
3605 NICKSERV_MIN_PARMS(2);
3606 gettimeofday(&start
, NULL
);
3607 if (!(db
= parse_database(argv
[1]))) {
3608 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3611 nickserv_saxdb_read(db
);
3613 gettimeofday(&stop
, NULL
);
3614 stop
.tv_sec
-= start
.tv_sec
;
3615 stop
.tv_usec
-= start
.tv_usec
;
3616 if (stop
.tv_usec
< 0) {
3618 stop
.tv_usec
+= 1000000;
3620 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3625 expire_handles(UNUSED_ARG(void *data
))
3627 dict_iterator_t it
, next
;
3629 struct handle_info
*hi
;
3631 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3632 next
= iter_next(it
);
3634 if ((hi
->opserv_level
> 0)
3636 || HANDLE_FLAGGED(hi
, FROZEN
)
3637 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3640 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3641 if ((now
- hi
->lastseen
) > expiry
) {
3642 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3643 nickserv_unregister_handle(hi
, NULL
);
3647 if (nickserv_conf
.handle_expire_frequency
)
3648 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3652 nickserv_load_dict(const char *fname
)
3656 if (!(file
= fopen(fname
, "r"))) {
3657 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3660 while (!feof(file
)) {
3661 fgets(line
, sizeof(line
), file
);
3664 if (line
[strlen(line
)-1] == '\n')
3665 line
[strlen(line
)-1] = 0;
3666 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3669 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3672 static enum reclaim_action
3673 reclaim_action_from_string(const char *str
) {
3675 return RECLAIM_NONE
;
3676 else if (!irccasecmp(str
, "warn"))
3677 return RECLAIM_WARN
;
3678 else if (!irccasecmp(str
, "svsnick"))
3679 return RECLAIM_SVSNICK
;
3680 else if (!irccasecmp(str
, "kill"))
3681 return RECLAIM_KILL
;
3683 return RECLAIM_NONE
;
3687 nickserv_conf_read(void)
3689 dict_t conf_node
, child
;
3693 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3694 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3697 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3699 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3700 if (nickserv_conf
.valid_handle_regex_set
)
3701 regfree(&nickserv_conf
.valid_handle_regex
);
3703 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3704 nickserv_conf
.valid_handle_regex_set
= !err
;
3705 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3707 nickserv_conf
.valid_handle_regex_set
= 0;
3709 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3710 if (nickserv_conf
.valid_nick_regex_set
)
3711 regfree(&nickserv_conf
.valid_nick_regex
);
3713 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3714 nickserv_conf
.valid_nick_regex_set
= !err
;
3715 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3717 nickserv_conf
.valid_nick_regex_set
= 0;
3719 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3721 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3722 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3723 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3724 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3725 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3726 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3727 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3728 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3729 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3730 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3731 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3732 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3733 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3734 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3735 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3736 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3737 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3738 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3739 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3740 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3741 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3742 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3743 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3744 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3745 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3747 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3748 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3749 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3751 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3752 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3753 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3755 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3756 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3757 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3758 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3759 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3760 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3761 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3762 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3763 if (!nickserv_conf
.disable_nicks
) {
3764 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3765 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3766 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3767 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3768 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3769 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3770 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3771 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3773 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3774 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3775 const char *key
= iter_key(it
), *value
;
3779 if (!strncasecmp(key
, "uc_", 3))
3780 flag
= toupper(key
[3]);
3781 else if (!strncasecmp(key
, "lc_", 3))
3782 flag
= tolower(key
[3]);
3786 if ((pos
= handle_inverse_flags
[flag
])) {
3787 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3788 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3791 if (nickserv_conf
.weak_password_dict
)
3792 dict_delete(nickserv_conf
.weak_password_dict
);
3793 nickserv_conf
.weak_password_dict
= dict_new();
3794 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3795 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3796 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3797 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3799 nickserv_load_dict(str
);
3800 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3801 if (nickserv
&& str
)
3802 NickChange(nickserv
, str
, 0);
3803 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3804 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3805 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3806 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3807 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3808 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3809 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3810 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3811 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3812 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3813 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3814 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3815 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3816 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3817 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3818 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3819 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3820 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3821 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3822 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3824 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
3825 nickserv_conf
.auto_oper
= str
? str
: "";
3827 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
3828 nickserv_conf
.auto_admin
= str
? str
: "";
3830 str
= conf_get_data("server/network", RECDB_QSTRING
);
3831 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3832 if (!nickserv_conf
.auth_policer_params
) {
3833 nickserv_conf
.auth_policer_params
= policer_params_new();
3834 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3835 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3837 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3838 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3839 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3843 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3845 char newnick
[NICKLEN
+1];
3854 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3856 case RECLAIM_SVSNICK
:
3858 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3859 } while (GetUserH(newnick
));
3860 irc_svsnick(nickserv
, user
, newnick
);
3863 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3864 irc_kill(nickserv
, user
, msg
);
3870 nickserv_reclaim_p(void *data
) {
3871 struct userNode
*user
= data
;
3872 struct nick_info
*ni
= get_nick_info(user
->nick
);
3874 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3878 check_user_nick(struct userNode
*user
) {
3879 struct nick_info
*ni
;
3880 user
->modes
&= ~FLAGS_REGNICK
;
3881 if (!(ni
= get_nick_info(user
->nick
)))
3883 if (user
->handle_info
== ni
->owner
) {
3884 user
->modes
|= FLAGS_REGNICK
;
3888 if (nickserv_conf
.warn_nick_owned
)
3889 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3890 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3892 if (nickserv_conf
.auto_reclaim_delay
)
3893 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3895 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3900 handle_new_user(struct userNode
*user
)
3902 return check_user_nick(user
);
3906 handle_account(struct userNode
*user
, const char *stamp
)
3908 struct handle_info
*hi
;
3911 #ifdef WITH_PROTOCOL_P10
3912 time_t timestamp
= 0;
3914 colon
= strchr(stamp
, ':');
3915 if(colon
&& colon
[1])
3918 timestamp
= atoi(colon
+1);
3920 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3921 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3923 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
);
3927 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3928 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
3932 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3935 set_user_handle_info(user
, hi
, 0);
3937 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
3942 handle_nick_change(struct userNode
*user
, const char *old_nick
)
3944 struct handle_info
*hi
;
3946 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
3947 dict_remove(nickserv_allow_auth_dict
, old_nick
);
3948 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
3950 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3951 check_user_nick(user
);
3955 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
3957 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
3958 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3959 set_user_handle_info(user
, NULL
, 0);
3962 static struct modcmd
*
3963 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
3965 if (min_level
> 0) {
3967 sprintf(buf
, "%u", min_level
);
3968 if (must_be_qualified
) {
3969 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
3971 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
3973 } else if (min_level
== 0) {
3974 if (must_be_qualified
) {
3975 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3977 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3980 if (must_be_qualified
) {
3981 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
3983 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
3989 nickserv_db_cleanup(void)
3991 unreg_del_user_func(nickserv_remove_user
);
3992 userList_clean(&curr_helpers
);
3993 policer_params_delete(nickserv_conf
.auth_policer_params
);
3994 dict_delete(nickserv_handle_dict
);
3995 dict_delete(nickserv_nick_dict
);
3996 dict_delete(nickserv_opt_dict
);
3997 dict_delete(nickserv_allow_auth_dict
);
3998 dict_delete(nickserv_email_dict
);
3999 dict_delete(nickserv_id_dict
);
4000 dict_delete(nickserv_conf
.weak_password_dict
);
4001 free(auth_func_list
);
4002 free(unreg_func_list
);
4004 free(allowauth_func_list
);
4005 free(handle_merge_func_list
);
4006 free(failpw_func_list
);
4007 if (nickserv_conf
.valid_handle_regex_set
)
4008 regfree(&nickserv_conf
.valid_handle_regex
);
4009 if (nickserv_conf
.valid_nick_regex_set
)
4010 regfree(&nickserv_conf
.valid_nick_regex
);
4014 init_nickserv(const char *nick
)
4017 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4018 reg_new_user_func(handle_new_user
);
4019 reg_nick_change_func(handle_nick_change
);
4020 reg_del_user_func(nickserv_remove_user
);
4021 reg_account_func(handle_account
);
4023 /* set up handle_inverse_flags */
4024 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4025 for (i
=0; handle_flags
[i
]; i
++) {
4026 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4027 flag_access_levels
[i
] = 0;
4030 conf_register_reload(nickserv_conf_read
);
4031 nickserv_opt_dict
= dict_new();
4032 nickserv_email_dict
= dict_new();
4033 dict_set_free_keys(nickserv_email_dict
, free
);
4034 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4036 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4037 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4038 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4039 * a big pain to disable since its nolonger in the config file. ) -Rubin
4041 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4042 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4043 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4044 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4045 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4046 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4047 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4048 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4049 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4050 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4051 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4052 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4053 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4054 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4055 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4056 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4057 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4058 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4059 if (!nickserv_conf
.disable_nicks
) {
4060 /* nick management commands */
4061 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4062 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4063 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4064 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4065 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4066 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4068 if (nickserv_conf
.email_enabled
) {
4069 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4070 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4071 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4072 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4073 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4074 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4076 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4077 /* miscellaneous commands */
4078 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4079 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4080 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4081 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4082 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4084 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4085 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4086 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4087 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4088 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4089 /* dict_insert(nickserv_opt_dict, "STYLE", opt_style); */
4090 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4091 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4092 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4093 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4094 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4095 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4096 if (nickserv_conf
.titlehost_suffix
) {
4097 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4098 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4100 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4101 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4102 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4104 nickserv_handle_dict
= dict_new();
4105 dict_set_free_keys(nickserv_handle_dict
, free
);
4106 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4108 nickserv_id_dict
= dict_new();
4109 dict_set_free_keys(nickserv_id_dict
, free
);
4111 nickserv_nick_dict
= dict_new();
4112 dict_set_free_data(nickserv_nick_dict
, free
);
4114 nickserv_allow_auth_dict
= dict_new();
4116 userList_init(&curr_helpers
);
4119 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4120 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4121 nickserv_service
= service_register(nickserv
);
4123 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4124 reg_exit_func(nickserv_db_cleanup
);
4125 if(nickserv_conf
.handle_expire_frequency
)
4126 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4127 message_register_table(msgtab
);