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"
103 #define KEY_NOTE_NOTE "note"
104 #define KEY_NOTE_SETTER "setter"
105 #define KEY_NOTE_DATE "date"
108 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
110 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
111 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
112 typedef OPTION_FUNC(option_func_t
);
114 DEFINE_LIST(handle_info_list
, struct handle_info
*);
116 #define NICKSERV_MIN_PARMS(N) do { \
118 reply("MSG_MISSING_PARAMS", argv[0]); \
119 svccmd_send_help_brief(user, nickserv, cmd); \
123 struct userNode
*nickserv
;
124 struct userList curr_helpers
;
125 const char *handle_flags
= HANDLE_FLAGS
;
127 static struct module *nickserv_module
;
128 static struct service
*nickserv_service
;
129 static struct log_type
*NS_LOG
;
130 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
131 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
132 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
133 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
134 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
135 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
136 static char handle_inverse_flags
[256];
137 static unsigned int flag_access_levels
[32];
138 static const struct message_entry msgtab
[] = {
139 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
140 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
141 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
142 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
143 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
144 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
145 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
146 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
147 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
148 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
149 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
150 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
151 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
152 { "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." },
153 { "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." },
154 { "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." },
155 { "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." },
156 { "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." },
157 { "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." },
158 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
159 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
160 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
161 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
162 { "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." },
163 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
164 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
165 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
166 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
167 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
168 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
169 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
170 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
171 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
172 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
173 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
174 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
175 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
176 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
177 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
178 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
179 { "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)" },
180 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
181 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
182 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
183 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
184 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
185 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
186 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
187 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
188 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
189 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
190 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
191 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
192 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
193 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
194 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
195 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
196 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
197 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
198 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
199 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
200 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
201 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
202 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
203 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
204 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
205 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
206 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
207 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
208 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
209 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
210 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
211 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
212 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
213 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
214 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
215 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
216 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
217 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
218 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
219 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
220 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
221 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
222 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
223 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
224 { "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)." },
225 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
226 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
227 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
228 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
229 { "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." },
230 { "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." },
231 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
232 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
233 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
234 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
235 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
236 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
237 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
238 { "NSMSG_PASS_SUCCESS", "Password changed." },
239 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
240 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
241 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
242 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
243 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
244 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
245 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
246 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
247 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
248 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
249 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
250 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
251 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
252 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
253 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
254 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
255 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
256 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
257 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
258 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
259 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
260 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
261 { "NSMSG_NO_ACCESS", "Access denied." },
262 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
263 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
264 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
265 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
266 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
267 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
268 { "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." },
269 { "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." },
270 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
271 { "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." },
272 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
273 { "NSMSG_SEARCH_MATCH", "Match: %s" },
274 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
275 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
276 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
277 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
278 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
279 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
280 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
281 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
282 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
283 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
284 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
285 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
286 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
287 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
288 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
289 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
290 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
291 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
292 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
293 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
294 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
295 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
296 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
297 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
298 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
299 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
300 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
301 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
302 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
303 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
304 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
305 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
306 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
308 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
309 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
311 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
312 { "NSEMAIL_ACTIVATION_BODY",
313 "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"
315 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
316 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
317 "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"
318 "/msg %3$s@%4$s AUTH %5$s your-password\n"
319 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
320 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
322 "If you did NOT request this account, you do not need to do anything.\n"
323 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
324 { "NSEMAIL_ACTIVATION_BODY_WEB",
325 "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"
327 "To verify your email address and complete the account registration, visit the following URL:\n"
328 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
330 "If you did NOT request this account, you do not need to do anything.\n"
331 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
332 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
333 { "NSEMAIL_PASSWORD_CHANGE_BODY",
334 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
335 "To complete the password change, log on to %1$s and type the following command:\n"
336 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
337 "If you did NOT request your password to be changed, you do not need to do anything.\n"
338 "Please contact the %1$s staff if you have questions." },
339 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
340 "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"
341 "To complete the password change, click the following URL:\n"
342 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
343 "If you did NOT request your password to be changed, you do not need to do anything.\n"
344 "Please contact the %1$s staff if you have questions." },
345 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
346 #ifdef stupid_verify_old_email
347 { "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." },
348 { "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." },
350 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
351 { "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." },
352 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
353 { "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." },
354 { "CHECKPASS_YES", "Yes." },
355 { "CHECKPASS_NO", "No." },
359 enum reclaim_action
{
365 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
366 static void nickserv_reclaim_p(void *data
);
369 unsigned int disable_nicks
: 1;
370 unsigned int valid_handle_regex_set
: 1;
371 unsigned int valid_nick_regex_set
: 1;
372 unsigned int autogag_enabled
: 1;
373 unsigned int email_enabled
: 1;
374 unsigned int email_required
: 1;
375 unsigned int default_hostmask
: 1;
376 unsigned int warn_nick_owned
: 1;
377 unsigned int warn_clone_auth
: 1;
378 unsigned int sync_log
: 1;
379 unsigned long nicks_per_handle
;
380 unsigned long password_min_length
;
381 unsigned long password_min_digits
;
382 unsigned long password_min_upper
;
383 unsigned long password_min_lower
;
384 unsigned long db_backup_frequency
;
385 unsigned long handle_expire_frequency
;
386 unsigned long autogag_duration
;
387 unsigned long email_visible_level
;
388 unsigned long cookie_timeout
;
389 unsigned long handle_expire_delay
;
390 unsigned long nochan_handle_expire_delay
;
391 unsigned long modoper_level
;
392 unsigned long set_epithet_level
;
393 unsigned long set_title_level
;
394 unsigned long set_fakehost_level
;
395 unsigned long handles_per_email
;
396 unsigned long email_search_level
;
397 const char *network_name
;
398 const char *titlehost_suffix
;
399 regex_t valid_handle_regex
;
400 regex_t valid_nick_regex
;
401 dict_t weak_password_dict
;
402 struct policer_params
*auth_policer_params
;
403 enum reclaim_action reclaim_action
;
404 enum reclaim_action auto_reclaim_action
;
405 unsigned long auto_reclaim_delay
;
406 unsigned char default_maxlogins
;
407 unsigned char hard_maxlogins
;
408 const char *auto_oper
;
409 const char *auto_admin
;
412 /* We have 2^32 unique account IDs to use. */
413 unsigned long int highest_id
= 0;
416 canonicalize_hostmask(char *mask
)
418 char *out
= mask
, *temp
;
419 if ((temp
= strchr(mask
, '!'))) {
421 while (*temp
) *out
++ = *temp
++;
427 static struct handle_note
*
428 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
430 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
432 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
434 memcpy(note
->note
, text
, strlen(text
));
438 static struct handle_info
*
439 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
441 struct handle_info
*hi
;
443 #ifdef WITH_PROTOCOL_BAHAMUT
444 char id_base64
[IDLEN
+ 1];
447 /* Assign a unique account ID to the account; note that 0 is
448 an invalid account ID. 1 is therefore the first account ID. */
450 id
= 1 + highest_id
++;
452 /* Note: highest_id is and must always be the highest ID. */
453 if(id
> highest_id
) {
457 inttobase64(id_base64
, id
, IDLEN
);
459 /* Make sure an account with the same ID doesn't exist. If a
460 duplicate is found, log some details and assign a new one.
461 This should be impossible, but it never hurts to expect it. */
462 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
463 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
469 hi
= calloc(1, sizeof(*hi
));
470 hi
->userlist_style
= HI_DEFAULT_STYLE
;
471 hi
->announcements
= '?';
472 hi
->handle
= strdup(handle
);
473 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
475 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
477 #ifdef WITH_PROTOCOL_BAHAMUT
479 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
486 register_nick(const char *nick
, struct handle_info
*owner
)
488 struct nick_info
*ni
;
489 ni
= malloc(sizeof(struct nick_info
));
490 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
492 ni
->next
= owner
->nicks
;
494 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
498 delete_nick(struct nick_info
*ni
)
500 struct nick_info
*last
, *next
;
501 struct userNode
*user
;
502 /* Check to see if we should mark a user as unregistered. */
503 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
504 user
->modes
&= ~FLAGS_REGNICK
;
507 /* Remove ni from the nick_info linked list. */
508 if (ni
== ni
->owner
->nicks
) {
509 ni
->owner
->nicks
= ni
->next
;
511 last
= ni
->owner
->nicks
;
517 last
->next
= next
->next
;
519 dict_remove(nickserv_nick_dict
, ni
->nick
);
522 static unreg_func_t
*unreg_func_list
;
523 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
526 reg_unreg_func(unreg_func_t func
)
528 if (unreg_func_used
== unreg_func_size
) {
529 if (unreg_func_size
) {
530 unreg_func_size
<<= 1;
531 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
534 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
537 unreg_func_list
[unreg_func_used
++] = func
;
541 nickserv_free_cookie(void *data
)
543 struct handle_cookie
*cookie
= data
;
544 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
545 if (cookie
->data
) free(cookie
->data
);
550 free_handle_info(void *vhi
)
552 struct handle_info
*hi
= vhi
;
554 #ifdef WITH_PROTOCOL_BAHAMUT
557 inttobase64(id
, hi
->id
, IDLEN
);
558 dict_remove(nickserv_id_dict
, id
);
561 free_string_list(hi
->masks
);
565 delete_nick(hi
->nicks
);
571 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
572 nickserv_free_cookie(hi
->cookie
);
574 if (hi
->email_addr
) {
575 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
576 handle_info_list_remove(hil
, hi
);
578 dict_remove(nickserv_email_dict
, hi
->email_addr
);
583 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
586 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
589 struct userNode
*uNode
;
591 for (n
=0; n
<unreg_func_used
; n
++)
592 unreg_func_list
[n
](notify
, hi
);
594 if (nickserv_conf
.sync_log
) {
595 uNode
= GetUserH(hi
->users
->nick
);
599 set_user_handle_info(hi
->users
, NULL
, 0);
602 if (nickserv_conf
.disable_nicks
)
603 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
605 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
608 if (nickserv_conf
.sync_log
)
609 SyncLog("UNREGISTER %s", hi
->handle
);
611 dict_remove(nickserv_handle_dict
, hi
->handle
);
615 get_handle_info(const char *handle
)
617 return dict_find(nickserv_handle_dict
, handle
, 0);
621 get_nick_info(const char *nick
)
623 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
627 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
632 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
633 mn
= channel
->members
.list
[nn
];
634 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
641 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
642 if (!user
->handle_info
) {
644 send_message(user
, bot
, "MSG_AUTHENTICATE");
648 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
650 send_message(user
, bot
, "NSMSG_NO_ACCESS");
654 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
656 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
660 if (user
->handle_info
->opserv_level
< min_level
) {
662 send_message(user
, bot
, "NSMSG_NO_ACCESS");
670 is_valid_handle(const char *handle
)
672 struct userNode
*user
;
673 /* cant register a juped nick/service nick as handle, to prevent confusion */
674 user
= GetUserH(handle
);
675 if (user
&& IsLocal(user
))
677 /* check against maximum length */
678 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
680 /* for consistency, only allow account names that could be nicks */
681 if (!is_valid_nick(handle
))
683 /* disallow account names that look like bad words */
684 if (opserv_bad_channel(handle
))
686 /* test either regex or containing all valid chars */
687 if (nickserv_conf
.valid_handle_regex_set
) {
688 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
691 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
692 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
696 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
701 is_registerable_nick(const char *nick
)
703 /* make sure it could be used as an account name */
704 if (!is_valid_handle(nick
))
707 if (strlen(nick
) > NICKLEN
)
709 /* test either regex or as valid handle */
710 if (nickserv_conf
.valid_nick_regex_set
) {
711 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
714 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
715 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
723 is_valid_email_addr(const char *email
)
725 return strchr(email
, '@') != NULL
;
729 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
731 if (hi
->email_addr
) {
732 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
733 return hi
->email_addr
;
743 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
745 struct handle_info
*hi
;
746 struct userNode
*target
;
750 if (!(hi
= get_handle_info(++name
))) {
751 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
756 if (!(target
= GetUserH(name
))) {
757 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
760 if (IsLocal(target
)) {
761 if (IsService(target
))
762 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
764 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
767 if (!(hi
= target
->handle_info
)) {
768 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
776 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
777 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
779 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
780 if ((user
->handle_info
->opserv_level
== 1000)
781 || (user
->handle_info
== hi
)
782 || ((user
->handle_info
->opserv_level
== 0)
783 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
784 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
788 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
792 static struct handle_info
*
793 get_victim_oper(struct userNode
*user
, const char *target
)
795 struct handle_info
*hi
;
796 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
798 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
799 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
802 return oper_outranks(user
, hi
) ? hi
: NULL
;
806 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
810 /* If no hostmasks on the account, allow it. */
811 if (!hi
->masks
->used
)
813 /* If any hostmask matches, allow it. */
814 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
815 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
817 /* If they are allowauthed to this account, allow it (removing the aa). */
818 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
819 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
822 /* The user is not allowed to use this account. */
827 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
830 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
834 if (len
< nickserv_conf
.password_min_length
) {
836 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
839 if (!irccasecmp(pass
, handle
)) {
841 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
844 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
847 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
850 for (i
=0; i
<len
; i
++) {
851 if (isdigit(pass
[i
]))
853 if (isupper(pass
[i
]))
855 if (islower(pass
[i
]))
858 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
859 || (cnt_upper
< nickserv_conf
.password_min_upper
)
860 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
862 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
868 static auth_func_t
*auth_func_list
;
869 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
872 reg_auth_func(auth_func_t func
)
874 if (auth_func_used
== auth_func_size
) {
875 if (auth_func_size
) {
876 auth_func_size
<<= 1;
877 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
880 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
883 auth_func_list
[auth_func_used
++] = func
;
886 static handle_rename_func_t
*rf_list
;
887 static unsigned int rf_list_size
, rf_list_used
;
890 reg_handle_rename_func(handle_rename_func_t func
)
892 if (rf_list_used
== rf_list_size
) {
895 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
898 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
901 rf_list
[rf_list_used
++] = func
;
905 generate_fakehost(struct handle_info
*handle
)
907 extern const char *hidden_host_suffix
;
908 static char buffer
[HOSTLEN
+1];
910 if (!handle
->fakehost
) {
911 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
913 } else if (handle
->fakehost
[0] == '.') {
914 /* A leading dot indicates the stored value is actually a title. */
915 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
918 return handle
->fakehost
;
922 apply_fakehost(struct handle_info
*handle
)
924 struct userNode
*target
;
929 fake
= generate_fakehost(handle
);
930 for (target
= handle
->users
; target
; target
= target
->next_authed
)
931 assign_fakehost(target
, fake
, 1);
934 void send_func_list(struct userNode
*user
)
937 struct handle_info
*old_info
;
939 old_info
= user
->handle_info
;
941 for (n
=0; n
<auth_func_used
; n
++)
942 auth_func_list
[n
](user
, old_info
);
946 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
949 struct handle_info
*old_info
;
951 /* This can happen if somebody uses COOKIE while authed, or if
952 * they re-auth to their current handle (which is silly, but users
954 if (user
->handle_info
== hi
)
957 if (user
->handle_info
) {
958 struct userNode
*other
;
961 userList_remove(&curr_helpers
, user
);
963 /* remove from next_authed linked list */
964 if (user
->handle_info
->users
== user
) {
965 user
->handle_info
->users
= user
->next_authed
;
967 for (other
= user
->handle_info
->users
;
968 other
->next_authed
!= user
;
969 other
= other
->next_authed
) ;
970 other
->next_authed
= user
->next_authed
;
972 /* if nobody left on old handle, and they're not an oper, remove !god */
973 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
974 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
975 /* record them as being last seen at this time */
976 user
->handle_info
->lastseen
= now
;
977 /* and record their hostmask */
978 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
980 old_info
= user
->handle_info
;
981 user
->handle_info
= hi
;
982 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
983 HANDLE_CLEAR_FLAG(hi
, HELPING
);
985 if (GetUserH(user
->nick
)) {
986 for (n
=0; n
<auth_func_used
; n
++)
987 auth_func_list
[n
](user
, old_info
);
992 struct nick_info
*ni
;
994 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
995 if (nickserv_conf
.warn_clone_auth
) {
996 struct userNode
*other
;
997 for (other
= hi
->users
; other
; other
= other
->next_authed
)
998 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1001 user
->next_authed
= hi
->users
;
1005 userList_append(&curr_helpers
, user
);
1007 if (hi
->fakehost
|| old_info
)
1011 #ifdef WITH_PROTOCOL_BAHAMUT
1012 /* Stamp users with their account ID. */
1014 inttobase64(id
, hi
->id
, IDLEN
);
1015 #elif WITH_PROTOCOL_P10
1016 /* Stamp users with their account name. */
1017 char *id
= hi
->handle
;
1019 const char *id
= "???";
1021 if (!nickserv_conf
.disable_nicks
) {
1022 struct nick_info
*ni
;
1023 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1024 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1025 user
->modes
|= FLAGS_REGNICK
;
1030 StampUser(user
, id
, hi
->registered
);
1033 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1034 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1036 /* We cannot clear the user's account ID, unfortunately. */
1037 user
->next_authed
= NULL
;
1041 static struct handle_info
*
1042 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1044 struct handle_info
*hi
;
1045 struct nick_info
*ni
;
1046 char crypted
[MD5_CRYPT_LENGTH
];
1048 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1049 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1053 if(strlen(handle
) > 15)
1055 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1059 if (!is_secure_password(handle
, passwd
, user
))
1062 cryptpass(passwd
, crypted
);
1063 hi
= register_handle(handle
, crypted
, 0);
1064 hi
->masks
= alloc_string_list(1);
1066 hi
->language
= lang_C
;
1067 hi
->registered
= now
;
1069 hi
->flags
= HI_DEFAULT_FLAGS
;
1070 if (settee
&& !no_auth
)
1071 set_user_handle_info(settee
, hi
, 1);
1074 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1075 else if (nickserv_conf
.disable_nicks
)
1076 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1077 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1078 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1080 register_nick(user
->nick
, hi
);
1081 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1083 if (settee
&& (user
!= settee
))
1084 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1089 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1091 cookie
->hi
->cookie
= cookie
;
1092 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1095 /* Contributed by the great sneep of afternet ;) */
1096 /* Since this gets used in a URL, we want to avoid stuff that confuses
1097 * email clients such as ] and ?. a-z, 0-9 only.
1099 void genpass(char *str
, int len
)
1104 for(i
= 0; i
< len
; i
++)
1108 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1109 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1117 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1119 struct handle_cookie
*cookie
;
1120 char subject
[128], body
[4096], *misc
;
1121 const char *netname
, *fmt
;
1125 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1129 cookie
= calloc(1, sizeof(*cookie
));
1131 cookie
->type
= type
;
1132 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1134 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1135 /* Adding dedicated password gen function for more control -Rubin */
1136 genpass(cookie
->cookie
, 10);
1138 *inttobase64(cookie->cookie, rand(), 5);
1139 *inttobase64(cookie->cookie+5, rand(), 5);
1142 netname
= nickserv_conf
.network_name
;
1145 switch (cookie
->type
) {
1147 hi
->passwd
[0] = 0; /* invalidate password */
1148 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1149 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1150 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1153 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1155 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1157 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1160 case PASSWORD_CHANGE
:
1161 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1162 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1163 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1165 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1167 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1168 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1171 misc
= hi
->email_addr
;
1172 hi
->email_addr
= cookie
->data
;
1173 #ifdef stupid_verify_old_email
1175 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1176 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1177 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1178 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1179 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1180 sendmail(nickserv
, hi
, subject
, body
, 1);
1181 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1182 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1185 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1186 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1187 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1188 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1189 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1190 sendmail(nickserv
, hi
, subject
, body
, 1);
1192 #ifdef stupid_verify_old_email
1195 hi
->email_addr
= misc
;
1198 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1199 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1200 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1201 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1202 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1205 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1209 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1210 nickserv_bake_cookie(cookie
);
1214 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1216 cookie
->hi
->cookie
= NULL
;
1217 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1218 nickserv_free_cookie(cookie
);
1222 nickserv_free_email_addr(void *data
)
1224 handle_info_list_clean(data
);
1229 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1231 struct handle_info_list
*hil
;
1232 /* Remove from old handle_info_list ... */
1233 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1234 handle_info_list_remove(hil
, hi
);
1235 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1236 hi
->email_addr
= NULL
;
1238 /* Add to the new list.. */
1239 if (new_email_addr
) {
1240 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1241 hil
= calloc(1, sizeof(*hil
));
1242 hil
->tag
= strdup(new_email_addr
);
1243 handle_info_list_init(hil
);
1244 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1246 handle_info_list_append(hil
, hi
);
1247 hi
->email_addr
= hil
->tag
;
1251 static NICKSERV_FUNC(cmd_register
)
1253 struct handle_info
*hi
;
1254 const char *email_addr
, *password
;
1255 char syncpass
[MD5_CRYPT_LENGTH
];
1256 int no_auth
, weblink
;
1258 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1259 /* Require the first handle registered to belong to someone +o. */
1260 reply("NSMSG_REQUIRE_OPER");
1264 if (user
->handle_info
) {
1265 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1269 if (IsRegistering(user
)) {
1270 reply("NSMSG_ALREADY_REGISTERING");
1274 if (IsStamped(user
)) {
1275 /* Unauthenticated users might still have been stamped
1276 previously and could therefore have a hidden host;
1277 do not allow them to register a new account. */
1278 reply("NSMSG_STAMPED_REGISTER");
1282 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1284 if (!is_valid_handle(argv
[1])) {
1285 reply("NSMSG_BAD_HANDLE", argv
[1]);
1290 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1291 struct handle_info_list
*hil
;
1294 /* Remember email address. */
1295 email_addr
= argv
[3];
1297 /* Check that the email address looks valid.. */
1298 if (!is_valid_email_addr(email_addr
)) {
1299 reply("NSMSG_BAD_EMAIL_ADDR");
1303 /* .. and that we are allowed to send to it. */
1304 if ((str
= sendmail_prohibited_address(email_addr
))) {
1305 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1309 /* If we do email verify, make sure we don't spam the address. */
1310 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1312 for (nn
=0; nn
<hil
->used
; nn
++) {
1313 if (hil
->list
[nn
]->cookie
) {
1314 reply("NSMSG_EMAIL_UNACTIVATED");
1318 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1319 reply("NSMSG_EMAIL_OVERUSED");
1332 /* Webregister hack - send URL instead of IRC cookie
1335 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1339 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1341 /* Add any masks they should get. */
1342 if (nickserv_conf
.default_hostmask
) {
1343 string_list_append(hi
->masks
, strdup("*@*"));
1345 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1346 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1347 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1350 /* If they're the first to register, give them level 1000. */
1351 if (dict_size(nickserv_handle_dict
) == 1) {
1352 hi
->opserv_level
= 1000;
1353 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1356 /* Set their email address. */
1358 nickserv_set_email_addr(hi
, email_addr
);
1360 /* If they need to do email verification, tell them. */
1362 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1364 /* Set registering flag.. */
1365 user
->modes
|= FLAGS_REGISTERING
;
1367 if (nickserv_conf
.sync_log
) {
1368 cryptpass(password
, syncpass
);
1370 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1371 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1374 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1377 /* this wont work if email is required .. */
1378 process_adduser_pending(user
);
1383 static NICKSERV_FUNC(cmd_oregister
)
1386 struct userNode
*settee
;
1387 struct handle_info
*hi
;
1389 NICKSERV_MIN_PARMS(nickserv_conf
.email_required
? 5 : 4);
1391 if (!is_valid_handle(argv
[1])) {
1392 reply("NSMSG_BAD_HANDLE", argv
[1]);
1396 if (nickserv_conf
.email_required
) {
1397 if (!is_valid_email_addr(argv
[4])) {
1398 reply("NSMSG_BAD_EMAIL_ADDR");
1403 if (strchr(argv
[3], '@')) {
1404 mask
= canonicalize_hostmask(strdup(argv
[3]));
1406 settee
= GetUserH(nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1408 reply("MSG_NICK_UNKNOWN", nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1415 } else if ((settee
= GetUserH(argv
[3]))) {
1416 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1418 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1421 if (settee
&& settee
->handle_info
) {
1422 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1426 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1427 if (nickserv_conf
.email_required
) {
1428 nickserv_set_email_addr(hi
, argv
[4]);
1429 if (nickserv_conf
.sync_log
)
1430 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, argv
[4], user
->info
);
1435 string_list_append(hi
->masks
, mask
);
1439 static NICKSERV_FUNC(cmd_handleinfo
)
1442 unsigned int i
, pos
=0, herelen
;
1443 struct userNode
*target
, *next_un
;
1444 struct handle_info
*hi
;
1445 const char *nsmsg_none
;
1448 if (!(hi
= user
->handle_info
)) {
1449 reply("NSMSG_MUST_AUTH");
1452 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1456 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1457 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1459 #ifdef WITH_PROTOCOL_BAHAMUT
1460 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1462 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1465 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1466 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1468 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1471 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1472 if (HANDLE_FLAGGED(hi
, FROZEN
))
1473 reply("NSMSG_HANDLEINFO_VACATION");
1475 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1476 struct do_not_register
*dnr
;
1477 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1478 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1479 if (!oper_outranks(user
, hi
))
1481 } else if (hi
!= user
->handle_info
) {
1482 reply("NSMSG_HANDLEINFO_END");
1486 if (nickserv_conf
.email_enabled
)
1487 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1491 switch (hi
->cookie
->type
) {
1492 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1493 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1494 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1495 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1496 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1502 unsigned long flen
= 1;
1503 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1505 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1506 if (hi
->flags
& 1 << i
)
1507 flags
[flen
++] = handle_flags
[i
];
1509 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1511 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1514 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1515 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1516 || (hi
->opserv_level
> 0)) {
1517 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1520 if (IsHelping(user
) || IsOper(user
))
1525 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1526 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1531 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1533 if (hi
->last_quit_host
[0])
1534 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1536 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1538 if (nickserv_conf
.disable_nicks
) {
1539 /* nicks disabled; don't show anything about registered nicks */
1540 } else if (hi
->nicks
) {
1541 struct nick_info
*ni
, *next_ni
;
1542 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1543 herelen
= strlen(ni
->nick
);
1544 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1546 goto print_nicks_buff
;
1550 memcpy(buff
+pos
, ni
->nick
, herelen
);
1551 pos
+= herelen
; buff
[pos
++] = ' ';
1555 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1560 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1563 if (hi
->masks
->used
) {
1564 for (i
=0; i
< hi
->masks
->used
; i
++) {
1565 herelen
= strlen(hi
->masks
->list
[i
]);
1566 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1568 goto print_mask_buff
;
1570 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1571 pos
+= herelen
; buff
[pos
++] = ' ';
1572 if (i
+1 == hi
->masks
->used
) {
1575 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1580 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1584 struct userData
*channel
, *next
;
1587 for (channel
= hi
->channels
; channel
; channel
= next
) {
1588 next
= channel
->u_next
;
1589 name
= channel
->channel
->channel
->name
;
1590 herelen
= strlen(name
);
1591 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1593 goto print_chans_buff
;
1595 if (IsUserSuspended(channel
))
1597 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1601 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1606 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1609 for (target
= hi
->users
; target
; target
= next_un
) {
1610 herelen
= strlen(target
->nick
);
1611 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1613 goto print_cnick_buff
;
1615 next_un
= target
->next_authed
;
1617 memcpy(buff
+pos
, target
->nick
, herelen
);
1618 pos
+= herelen
; buff
[pos
++] = ' ';
1622 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1627 reply("NSMSG_HANDLEINFO_END");
1631 static NICKSERV_FUNC(cmd_userinfo
)
1633 struct userNode
*target
;
1635 NICKSERV_MIN_PARMS(2);
1636 if (!(target
= GetUserH(argv
[1]))) {
1637 reply("MSG_NICK_UNKNOWN", argv
[1]);
1640 if (target
->handle_info
)
1641 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1643 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1647 static NICKSERV_FUNC(cmd_nickinfo
)
1649 struct nick_info
*ni
;
1651 NICKSERV_MIN_PARMS(2);
1652 if (!(ni
= get_nick_info(argv
[1]))) {
1653 reply("MSG_NICK_UNKNOWN", argv
[1]);
1656 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1660 static NICKSERV_FUNC(cmd_rename_handle
)
1662 struct handle_info
*hi
;
1663 struct userNode
*uNode
;
1664 char msgbuf
[MAXLEN
], *old_handle
;
1667 NICKSERV_MIN_PARMS(3);
1668 if (!(hi
= get_victim_oper(user
, argv
[1])))
1670 if (!is_valid_handle(argv
[2])) {
1671 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1674 if (get_handle_info(argv
[2])) {
1675 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1678 if(strlen(argv
[2]) > 15)
1680 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1684 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1685 hi
->handle
= strdup(argv
[2]);
1686 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1687 for (nn
=0; nn
<rf_list_used
; nn
++)
1688 rf_list
[nn
](hi
, old_handle
);
1689 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1692 if (nickserv_conf
.sync_log
) {
1693 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1694 irc_rename(uNode
, hi
->handle
);
1696 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1699 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1700 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1705 static failpw_func_t
*failpw_func_list
;
1706 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1709 reg_failpw_func(failpw_func_t func
)
1711 if (failpw_func_used
== failpw_func_size
) {
1712 if (failpw_func_size
) {
1713 failpw_func_size
<<= 1;
1714 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1716 failpw_func_size
= 8;
1717 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1720 failpw_func_list
[failpw_func_used
++] = func
;
1724 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1726 * called by nefariouses enhanced AC login-on-connect code
1729 struct handle_info
*loc_auth(char *handle
, char *password
)
1731 int pw_arg
, used
, maxlogins
;
1734 struct handle_info
*hi
;
1735 struct userNode
*other
;
1737 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1743 /* We don't know the users hostname, or anything because they
1744 * havn't registered yet. So we can only allow LOC if your
1745 * account has *@* as a hostmask.
1747 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1749 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1758 /* Responses from here on look up the language used by the handle they asked about. */
1759 if (!checkpass(password
, hi
->passwd
)) {
1762 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1765 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1766 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1767 if (++used
>= maxlogins
) {
1774 static NICKSERV_FUNC(cmd_auth
)
1776 int pw_arg
, used
, maxlogins
;
1777 struct handle_info
*hi
;
1779 struct userNode
*other
;
1781 if (user
->handle_info
) {
1782 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1785 if (IsStamped(user
)) {
1786 /* Unauthenticated users might still have been stamped
1787 previously and could therefore have a hidden host;
1788 do not allow them to authenticate. */
1789 reply("NSMSG_STAMPED_AUTH");
1793 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1795 } else if (argc
== 2) {
1796 if (nickserv_conf
.disable_nicks
) {
1797 if (!(hi
= get_handle_info(user
->nick
))) {
1798 reply("NSMSG_HANDLE_NOT_FOUND");
1802 /* try to look up their handle from their nick */
1803 struct nick_info
*ni
;
1804 ni
= get_nick_info(user
->nick
);
1806 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1813 reply("MSG_MISSING_PARAMS", argv
[0]);
1814 svccmd_send_help_brief(user
, nickserv
, cmd
);
1818 reply("NSMSG_HANDLE_NOT_FOUND");
1821 /* Responses from here on look up the language used by the handle they asked about. */
1822 passwd
= argv
[pw_arg
];
1823 if (!valid_user_for(user
, hi
)) {
1824 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1825 send_message_type(4, user
, cmd
->parent
->bot
,
1826 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1829 send_message_type(4, user
, cmd
->parent
->bot
,
1830 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1832 argv
[pw_arg
] = "BADMASK";
1835 if (!checkpass(passwd
, hi
->passwd
)) {
1837 send_message_type(4, user
, cmd
->parent
->bot
,
1838 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1839 argv
[pw_arg
] = "BADPASS";
1840 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1841 if (nickserv_conf
.autogag_enabled
) {
1842 if (!user
->auth_policer
.params
) {
1843 user
->auth_policer
.last_req
= now
;
1844 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1846 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1848 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1849 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1850 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1852 argv
[pw_arg
] = "GAGGED";
1857 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1858 send_message_type(4, user
, cmd
->parent
->bot
,
1859 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1860 argv
[pw_arg
] = "SUSPENDED";
1863 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1864 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1865 if (++used
>= maxlogins
) {
1866 send_message_type(4, user
, cmd
->parent
->bot
,
1867 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1869 argv
[pw_arg
] = "MAXLOGINS";
1874 set_user_handle_info(user
, hi
, 1);
1875 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1876 reply("NSMSG_PLEASE_SET_EMAIL");
1877 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1878 reply("NSMSG_WEAK_PASSWORD");
1879 if (hi
->passwd
[0] != '$')
1880 cryptpass(passwd
, hi
->passwd
);
1882 /* If a channel was waiting for this user to auth,
1883 * finish adding them */
1884 process_adduser_pending(user
);
1886 reply("NSMSG_AUTH_SUCCESS");
1889 /* Set +x if autohide is on */
1890 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
1891 irc_umode(user
, "+x");
1893 if(!IsOper(user
)) /* If they arnt already opered.. */
1895 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
1896 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
1898 irc_umode(user
,nickserv_conf
.auto_admin
);
1899 reply("NSMSG_AUTO_OPER_ADMIN");
1901 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
1903 irc_umode(user
,nickserv_conf
.auto_oper
);
1904 reply("NSMSG_AUTO_OPER");
1908 /* Wipe out the pass for the logs */
1909 argv
[pw_arg
] = "****";
1913 static allowauth_func_t
*allowauth_func_list
;
1914 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1917 reg_allowauth_func(allowauth_func_t func
)
1919 if (allowauth_func_used
== allowauth_func_size
) {
1920 if (allowauth_func_size
) {
1921 allowauth_func_size
<<= 1;
1922 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1924 allowauth_func_size
= 8;
1925 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1928 allowauth_func_list
[allowauth_func_used
++] = func
;
1931 static NICKSERV_FUNC(cmd_allowauth
)
1933 struct userNode
*target
;
1934 struct handle_info
*hi
;
1937 NICKSERV_MIN_PARMS(2);
1938 if (!(target
= GetUserH(argv
[1]))) {
1939 reply("MSG_NICK_UNKNOWN", argv
[1]);
1942 if (target
->handle_info
) {
1943 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1946 if (IsStamped(target
)) {
1947 /* Unauthenticated users might still have been stamped
1948 previously and could therefore have a hidden host;
1949 do not allow them to authenticate to an account. */
1950 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1955 else if (!(hi
= get_handle_info(argv
[2]))) {
1956 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1960 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1961 reply("MSG_USER_OUTRANKED", hi
->handle
);
1964 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1965 || (hi
->opserv_level
> 0))
1966 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1967 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1970 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1971 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1972 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1973 if (nickserv_conf
.email_enabled
)
1974 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1976 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1977 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1979 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1981 for (n
=0; n
<allowauth_func_used
; n
++)
1982 allowauth_func_list
[n
](user
, target
, hi
);
1986 static NICKSERV_FUNC(cmd_authcookie
)
1988 struct handle_info
*hi
;
1990 NICKSERV_MIN_PARMS(2);
1991 if (user
->handle_info
) {
1992 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1995 if (IsStamped(user
)) {
1996 /* Unauthenticated users might still have been stamped
1997 previously and could therefore have a hidden host;
1998 do not allow them to authenticate to an account. */
1999 reply("NSMSG_STAMPED_AUTHCOOKIE");
2002 if (!(hi
= get_handle_info(argv
[1]))) {
2003 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2006 if (!hi
->email_addr
) {
2007 reply("MSG_SET_EMAIL_ADDR");
2010 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2014 static NICKSERV_FUNC(cmd_delcookie
)
2016 struct handle_info
*hi
;
2018 hi
= user
->handle_info
;
2020 reply("NSMSG_NO_COOKIE");
2023 switch (hi
->cookie
->type
) {
2026 reply("NSMSG_MUST_TIME_OUT");
2029 nickserv_eat_cookie(hi
->cookie
);
2030 reply("NSMSG_ATE_COOKIE");
2036 static NICKSERV_FUNC(cmd_odelcookie
)
2038 struct handle_info
*hi
;
2040 NICKSERV_MIN_PARMS(2);
2042 if (!(hi
= get_victim_oper(user
, argv
[1])))
2046 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2050 nickserv_eat_cookie(hi
->cookie
);
2051 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2056 static NICKSERV_FUNC(cmd_resetpass
)
2058 struct handle_info
*hi
;
2059 char crypted
[MD5_CRYPT_LENGTH
];
2062 NICKSERV_MIN_PARMS(3);
2063 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2067 if (user
->handle_info
) {
2068 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2071 if (IsStamped(user
)) {
2072 /* Unauthenticated users might still have been stamped
2073 previously and could therefore have a hidden host;
2074 do not allow them to activate an account. */
2075 reply("NSMSG_STAMPED_RESETPASS");
2078 if (!(hi
= get_handle_info(argv
[1]))) {
2079 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2082 if (!hi
->email_addr
) {
2083 reply("MSG_SET_EMAIL_ADDR");
2086 cryptpass(argv
[2], crypted
);
2088 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2092 static NICKSERV_FUNC(cmd_cookie
)
2094 struct handle_info
*hi
;
2097 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2100 NICKSERV_MIN_PARMS(3);
2101 if (!(hi
= get_handle_info(argv
[1]))) {
2102 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2108 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2109 reply("NSMSG_HANDLE_SUSPENDED");
2114 reply("NSMSG_NO_COOKIE");
2118 /* Check validity of operation before comparing cookie to
2119 * prohibit guessing by authed users. */
2120 if (user
->handle_info
2121 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2122 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2123 reply("NSMSG_CANNOT_COOKIE");
2127 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2128 reply("NSMSG_BAD_COOKIE");
2132 switch (hi
->cookie
->type
) {
2134 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2135 set_user_handle_info(user
, hi
, 1);
2136 reply("NSMSG_HANDLE_ACTIVATED");
2137 if (nickserv_conf
.sync_log
)
2138 SyncLog("ACCOUNTACC %s", hi
->handle
);
2140 case PASSWORD_CHANGE
:
2141 set_user_handle_info(user
, hi
, 1);
2142 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2143 reply("NSMSG_PASSWORD_CHANGED");
2144 if (nickserv_conf
.sync_log
)
2145 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2148 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2150 * This should only happen if an OREGISTER was sent. Require
2151 * email must be enabled! - SiRVulcaN
2153 if (nickserv_conf
.sync_log
)
2154 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2156 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2157 reply("NSMSG_EMAIL_CHANGED");
2158 if (nickserv_conf
.sync_log
)
2159 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2162 set_user_handle_info(user
, hi
, 1);
2163 reply("NSMSG_AUTH_SUCCESS");
2166 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2167 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2171 nickserv_eat_cookie(hi
->cookie
);
2173 process_adduser_pending(user
);
2178 static NICKSERV_FUNC(cmd_oregnick
) {
2180 struct handle_info
*target
;
2181 struct nick_info
*ni
;
2183 NICKSERV_MIN_PARMS(3);
2184 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2187 if (!is_registerable_nick(nick
)) {
2188 reply("NSMSG_BAD_NICK", nick
);
2191 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2193 reply("NSMSG_NICK_EXISTS", nick
);
2196 register_nick(nick
, target
);
2197 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2201 static NICKSERV_FUNC(cmd_regnick
) {
2203 struct nick_info
*ni
;
2205 if (!is_registerable_nick(user
->nick
)) {
2206 reply("NSMSG_BAD_NICK", user
->nick
);
2209 /* count their nicks, see if it's too many */
2210 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2211 if (n
>= nickserv_conf
.nicks_per_handle
) {
2212 reply("NSMSG_TOO_MANY_NICKS");
2215 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2217 reply("NSMSG_NICK_EXISTS", user
->nick
);
2220 register_nick(user
->nick
, user
->handle_info
);
2221 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2225 static NICKSERV_FUNC(cmd_pass
)
2227 struct handle_info
*hi
;
2228 const char *old_pass
, *new_pass
;
2230 NICKSERV_MIN_PARMS(3);
2231 hi
= user
->handle_info
;
2235 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2236 if (!checkpass(old_pass
, hi
->passwd
)) {
2237 argv
[1] = "BADPASS";
2238 reply("NSMSG_PASSWORD_INVALID");
2241 cryptpass(new_pass
, hi
->passwd
);
2242 if (nickserv_conf
.sync_log
)
2243 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2245 reply("NSMSG_PASS_SUCCESS");
2250 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2253 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2254 for (i
=0; i
<hi
->masks
->used
; i
++) {
2255 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2256 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2261 string_list_append(hi
->masks
, new_mask
);
2262 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2266 static NICKSERV_FUNC(cmd_addmask
)
2269 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2270 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2274 if (!is_gline(argv
[1])) {
2275 reply("NSMSG_MASK_INVALID", argv
[1]);
2278 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2282 static NICKSERV_FUNC(cmd_oaddmask
)
2284 struct handle_info
*hi
;
2286 NICKSERV_MIN_PARMS(3);
2287 if (!(hi
= get_victim_oper(user
, argv
[1])))
2289 return nickserv_addmask(user
, hi
, argv
[2]);
2293 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2296 for (i
=0; i
<hi
->masks
->used
; i
++) {
2297 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2298 char *old_mask
= hi
->masks
->list
[i
];
2299 if (hi
->masks
->used
== 1) {
2300 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2303 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2304 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2309 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2313 static NICKSERV_FUNC(cmd_delmask
)
2315 NICKSERV_MIN_PARMS(2);
2316 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2319 static NICKSERV_FUNC(cmd_odelmask
)
2321 struct handle_info
*hi
;
2322 NICKSERV_MIN_PARMS(3);
2323 if (!(hi
= get_victim_oper(user
, argv
[1])))
2325 return nickserv_delmask(user
, hi
, argv
[2]);
2329 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2330 unsigned int nn
, add
= 1, pos
;
2331 unsigned long added
, removed
, flag
;
2333 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2335 case '+': add
= 1; break;
2336 case '-': add
= 0; break;
2338 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2339 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2342 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2343 /* cheesy avoidance of looking up the flag name.. */
2344 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2347 flag
= 1 << (pos
- 1);
2349 added
|= flag
, removed
&= ~flag
;
2351 removed
|= flag
, added
&= ~flag
;
2356 *premoved
= removed
;
2361 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2363 unsigned long before
, after
, added
, removed
;
2364 struct userNode
*uNode
;
2366 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2367 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2369 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2370 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2372 /* Strip helping flag if they're only a support helper and not
2373 * currently in #support. */
2374 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2375 struct channelList
*schannels
;
2377 schannels
= chanserv_support_channels();
2378 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2379 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2380 if (GetUserMode(schannels
->list
[ii
], uNode
))
2382 if (ii
< schannels
->used
)
2386 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2389 if (after
&& !before
) {
2390 /* Add user to current helper list. */
2391 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2392 userList_append(&curr_helpers
, uNode
);
2393 } else if (!after
&& before
) {
2394 /* Remove user from current helper list. */
2395 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2396 userList_remove(&curr_helpers
, uNode
);
2403 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2407 char *set_display
[] = {
2408 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", /* "STYLE", */
2409 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2410 "FAKEHOST", "TITLE", "EPITHET"
2413 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2414 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2416 /* Do this so options are presented in a consistent order. */
2417 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2418 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2419 opt(user
, hi
, override
, 0, NULL
);
2420 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2423 static NICKSERV_FUNC(cmd_set
)
2425 struct handle_info
*hi
;
2428 hi
= user
->handle_info
;
2430 set_list(user
, hi
, 0);
2433 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2434 reply("NSMSG_INVALID_OPTION", argv
[1]);
2437 return opt(user
, hi
, 0, argc
-1, argv
+1);
2440 static NICKSERV_FUNC(cmd_oset
)
2442 struct handle_info
*hi
;
2445 NICKSERV_MIN_PARMS(2);
2447 if (!(hi
= get_victim_oper(user
, argv
[1])))
2451 set_list(user
, hi
, 0);
2455 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2456 reply("NSMSG_INVALID_OPTION", argv
[2]);
2460 return opt(user
, hi
, 1, argc
-2, argv
+2);
2463 static OPTION_FUNC(opt_info
)
2467 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2469 hi
->infoline
= NULL
;
2471 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2475 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2476 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2480 static OPTION_FUNC(opt_width
)
2483 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2485 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2486 hi
->screen_width
= MIN_LINE_SIZE
;
2487 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2488 hi
->screen_width
= MAX_LINE_SIZE
;
2490 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2494 static OPTION_FUNC(opt_tablewidth
)
2497 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2499 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2500 hi
->table_width
= MIN_LINE_SIZE
;
2501 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2502 hi
->table_width
= MAX_LINE_SIZE
;
2504 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2508 static OPTION_FUNC(opt_color
)
2511 if (enabled_string(argv
[1]))
2512 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2513 else if (disabled_string(argv
[1]))
2514 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2516 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2521 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2525 static OPTION_FUNC(opt_privmsg
)
2528 if (enabled_string(argv
[1]))
2529 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2530 else if (disabled_string(argv
[1]))
2531 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2533 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2538 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2542 static OPTION_FUNC(opt_autohide
)
2545 if (enabled_string(argv
[1]))
2546 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2547 else if (disabled_string(argv
[1]))
2548 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2550 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2555 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2560 static OPTION_FUNC(opt_style)
2565 if (!irccasecmp(argv[1], "Zoot"))
2566 hi->userlist_style = HI_STYLE_ZOOT;
2567 else if (!irccasecmp(argv[1], "def"))
2568 hi->userlist_style = HI_STYLE_DEF;
2571 switch (hi->userlist_style) {
2580 send_message(user, nickserv, "NSMSG_SET_STYLE", style);
2585 static OPTION_FUNC(opt_announcements
)
2590 if (enabled_string(argv
[1]))
2591 hi
->announcements
= 'y';
2592 else if (disabled_string(argv
[1]))
2593 hi
->announcements
= 'n';
2594 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2595 hi
->announcements
= '?';
2597 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2602 switch (hi
->announcements
) {
2603 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2604 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2605 case '?': choice
= "default"; break;
2606 default: choice
= "unknown"; break;
2608 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2612 static OPTION_FUNC(opt_password
)
2615 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2620 cryptpass(argv
[1], hi
->passwd
);
2622 if (nickserv_conf
.sync_log
)
2623 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2625 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2629 static OPTION_FUNC(opt_flags
)
2632 unsigned int ii
, flen
;
2635 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2640 nickserv_apply_flags(user
, hi
, argv
[1]);
2642 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2643 if (hi
->flags
& (1 << ii
))
2644 flags
[flen
++] = handle_flags
[ii
];
2647 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2649 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2653 static OPTION_FUNC(opt_email
)
2657 if (!is_valid_email_addr(argv
[1])) {
2658 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2661 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2662 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2665 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2666 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2668 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2670 nickserv_set_email_addr(hi
, argv
[1]);
2672 nickserv_eat_cookie(hi
->cookie
);
2673 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2676 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2680 static OPTION_FUNC(opt_maxlogins
)
2682 unsigned char maxlogins
;
2684 maxlogins
= strtoul(argv
[1], NULL
, 0);
2685 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2686 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2689 hi
->maxlogins
= maxlogins
;
2691 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2692 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2696 static OPTION_FUNC(opt_language
)
2698 struct language
*lang
;
2700 lang
= language_find(argv
[1]);
2701 if (irccasecmp(lang
->name
, argv
[1]))
2702 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2703 hi
->language
= lang
;
2705 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2710 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2711 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2713 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2714 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2715 && (user
->handle_info
->opserv_level
< 1000))) {
2716 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2719 if ((user
->handle_info
->opserv_level
< new_level
)
2720 || ((user
->handle_info
->opserv_level
== new_level
)
2721 && (user
->handle_info
->opserv_level
< 1000))) {
2722 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2725 if (user
->handle_info
== target
) {
2726 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2729 if (target
->opserv_level
== new_level
)
2731 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2732 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2733 target
->opserv_level
= new_level
;
2737 static OPTION_FUNC(opt_level
)
2742 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2746 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2747 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2751 static OPTION_FUNC(opt_epithet
)
2753 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2756 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2760 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2764 if ((epithet
[0] == '*') && !epithet
[1])
2767 hi
->epithet
= strdup(epithet
);
2771 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2773 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2777 static OPTION_FUNC(opt_title
)
2781 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2783 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2788 if (strchr(title
, '.')) {
2789 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2792 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2793 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2794 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2799 if (!strcmp(title
, "*")) {
2800 hi
->fakehost
= NULL
;
2802 hi
->fakehost
= malloc(strlen(title
)+2);
2803 hi
->fakehost
[0] = '.';
2804 strcpy(hi
->fakehost
+1, title
);
2807 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2808 title
= hi
->fakehost
+ 1;
2812 title
= user_find_message(user
, "MSG_NONE");
2813 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2817 static OPTION_FUNC(opt_fakehost
)
2821 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2823 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2828 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2829 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2833 if (!strcmp(fake
, "*"))
2834 hi
->fakehost
= NULL
;
2836 hi
->fakehost
= strdup(fake
);
2837 fake
= hi
->fakehost
;
2840 fake
= generate_fakehost(hi
);
2842 fake
= user_find_message(user
, "MSG_NONE");
2843 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2847 static OPTION_FUNC(opt_note
)
2850 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2855 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
2860 if ((text
[0] == '*') && !text
[1])
2863 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
2868 send_message(user
, nickserv
, "NSMSG_SET_NOTE", hi
->note
->note
);
2872 static NICKSERV_FUNC(cmd_reclaim
)
2874 struct handle_info
*hi
;
2875 struct nick_info
*ni
;
2876 struct userNode
*victim
;
2878 NICKSERV_MIN_PARMS(2);
2879 hi
= user
->handle_info
;
2880 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2882 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2885 if (ni
->owner
!= user
->handle_info
) {
2886 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2889 victim
= GetUserH(ni
->nick
);
2891 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2894 if (victim
== user
) {
2895 reply("NSMSG_NICK_USER_YOU");
2898 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2899 switch (nickserv_conf
.reclaim_action
) {
2900 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2901 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2902 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2903 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2908 static NICKSERV_FUNC(cmd_unregnick
)
2911 struct handle_info
*hi
;
2912 struct nick_info
*ni
;
2914 hi
= user
->handle_info
;
2915 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2916 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2918 reply("NSMSG_UNKNOWN_NICK", nick
);
2921 if (hi
!= ni
->owner
) {
2922 reply("NSMSG_NOT_YOUR_NICK", nick
);
2925 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2930 static NICKSERV_FUNC(cmd_ounregnick
)
2932 struct nick_info
*ni
;
2934 NICKSERV_MIN_PARMS(2);
2935 if (!(ni
= get_nick_info(argv
[1]))) {
2936 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2939 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2940 reply("MSG_USER_OUTRANKED", ni
->nick
);
2943 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2948 static NICKSERV_FUNC(cmd_unregister
)
2950 struct handle_info
*hi
;
2953 NICKSERV_MIN_PARMS(2);
2954 hi
= user
->handle_info
;
2957 if (checkpass(passwd
, hi
->passwd
)) {
2958 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2961 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2962 reply("NSMSG_PASSWORD_INVALID");
2967 static NICKSERV_FUNC(cmd_ounregister
)
2969 struct handle_info
*hi
;
2971 NICKSERV_MIN_PARMS(2);
2972 if (!(hi
= get_victim_oper(user
, argv
[1])))
2974 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2978 static NICKSERV_FUNC(cmd_status
)
2980 if (nickserv_conf
.disable_nicks
) {
2981 reply("NSMSG_GLOBAL_STATS_NONICK",
2982 dict_size(nickserv_handle_dict
));
2984 if (user
->handle_info
) {
2986 struct nick_info
*ni
;
2987 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2988 reply("NSMSG_HANDLE_STATS", cnt
);
2990 reply("NSMSG_HANDLE_NONE");
2992 reply("NSMSG_GLOBAL_STATS",
2993 dict_size(nickserv_handle_dict
),
2994 dict_size(nickserv_nick_dict
));
2999 static NICKSERV_FUNC(cmd_ghost
)
3001 struct userNode
*target
;
3002 char reason
[MAXLEN
];
3004 NICKSERV_MIN_PARMS(2);
3005 if (!(target
= GetUserH(argv
[1]))) {
3006 reply("MSG_NICK_UNKNOWN", argv
[1]);
3009 if (target
== user
) {
3010 reply("NSMSG_CANNOT_GHOST_SELF");
3013 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3014 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3017 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3018 DelUser(target
, nickserv
, 1, reason
);
3019 reply("NSMSG_GHOST_KILLED", argv
[1]);
3023 static NICKSERV_FUNC(cmd_vacation
)
3025 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3026 reply("NSMSG_ON_VACATION");
3031 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3033 struct handle_info
*hi
;
3036 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3038 #ifdef WITH_PROTOCOL_BAHAMUT
3041 saxdb_start_record(ctx
, iter_key(it
), 0);
3042 if (hi
->announcements
!= '?') {
3043 flags
[0] = hi
->announcements
;
3045 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3048 struct handle_cookie
*cookie
= hi
->cookie
;
3051 switch (cookie
->type
) {
3052 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3053 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3054 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3055 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3056 default: type
= NULL
; break;
3059 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3060 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3061 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3063 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3064 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3065 saxdb_end_record(ctx
);
3069 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3071 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3073 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3074 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3075 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3076 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3077 saxdb_end_record(ctx
);
3081 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3085 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3086 if (hi
->flags
& (1 << ii
))
3087 flags
[flen
++] = handle_flags
[ii
];
3089 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3091 #ifdef WITH_PROTOCOL_BAHAMUT
3092 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3095 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3096 if (hi
->last_quit_host
[0])
3097 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3098 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3099 if (hi
->masks
->used
)
3100 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3102 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3104 struct string_list
*slist
;
3105 struct nick_info
*ni
;
3107 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3108 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3109 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3113 if (hi
->opserv_level
)
3114 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3115 if (hi
->language
!= lang_C
)
3116 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3117 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3118 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3119 if (hi
->screen_width
)
3120 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3121 if (hi
->table_width
)
3122 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3123 flags
[0] = hi
->userlist_style
;
3125 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3126 saxdb_end_record(ctx
);
3131 static handle_merge_func_t
*handle_merge_func_list
;
3132 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3135 reg_handle_merge_func(handle_merge_func_t func
)
3137 if (handle_merge_func_used
== handle_merge_func_size
) {
3138 if (handle_merge_func_size
) {
3139 handle_merge_func_size
<<= 1;
3140 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3142 handle_merge_func_size
= 8;
3143 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3146 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3149 static NICKSERV_FUNC(cmd_merge
)
3151 struct handle_info
*hi_from
, *hi_to
;
3152 struct userNode
*last_user
;
3153 struct userData
*cList
, *cListNext
;
3154 unsigned int ii
, jj
, n
;
3155 char buffer
[MAXLEN
];
3157 NICKSERV_MIN_PARMS(3);
3159 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3161 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3163 if (hi_to
== hi_from
) {
3164 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3168 for (n
=0; n
<handle_merge_func_used
; n
++)
3169 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3171 /* Append "from" handle's nicks to "to" handle's nick list. */
3173 struct nick_info
*last_ni
;
3174 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3175 last_ni
->next
= hi_from
->nicks
;
3177 while (hi_from
->nicks
) {
3178 hi_from
->nicks
->owner
= hi_to
;
3179 hi_from
->nicks
= hi_from
->nicks
->next
;
3182 /* Merge the hostmasks. */
3183 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3184 char *mask
= hi_from
->masks
->list
[ii
];
3185 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3186 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3188 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3189 string_list_append(hi_to
->masks
, strdup(mask
));
3192 /* Merge the lists of authed users. */
3194 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3195 last_user
->next_authed
= hi_from
->users
;
3197 hi_to
->users
= hi_from
->users
;
3199 /* Repoint the old "from" handle's users. */
3200 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3201 last_user
->handle_info
= hi_to
;
3203 hi_from
->users
= NULL
;
3205 /* Merge channel userlists. */
3206 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3207 struct userData
*cList2
;
3208 cListNext
= cList
->u_next
;
3209 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3210 if (cList
->channel
== cList2
->channel
)
3212 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3213 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
);
3214 /* keep cList2 in hi_to; remove cList from hi_from */
3215 del_channel_user(cList
, 1);
3218 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
);
3219 /* remove the lower-ranking cList2 from hi_to */
3220 del_channel_user(cList2
, 1);
3222 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3224 /* cList needs to be moved from hi_from to hi_to */
3225 cList
->handle
= hi_to
;
3226 /* Remove from linked list for hi_from */
3227 assert(!cList
->u_prev
);
3228 hi_from
->channels
= cList
->u_next
;
3230 cList
->u_next
->u_prev
= cList
->u_prev
;
3231 /* Add to linked list for hi_to */
3232 cList
->u_prev
= NULL
;
3233 cList
->u_next
= hi_to
->channels
;
3234 if (hi_to
->channels
)
3235 hi_to
->channels
->u_prev
= cList
;
3236 hi_to
->channels
= cList
;
3240 /* Do they get an OpServ level promotion? */
3241 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3242 hi_to
->opserv_level
= hi_from
->opserv_level
;
3244 /* What about last seen time? */
3245 if (hi_from
->lastseen
> hi_to
->lastseen
)
3246 hi_to
->lastseen
= hi_from
->lastseen
;
3248 /* Does a fakehost carry over? (This intentionally doesn't set it
3249 * for users previously attached to hi_to. They'll just have to
3252 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3253 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3255 /* Notify of success. */
3256 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3257 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3258 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3260 /* Unregister the "from" handle. */
3261 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3266 struct nickserv_discrim
{
3267 unsigned int limit
, min_level
, max_level
;
3268 unsigned long flags_on
, flags_off
;
3269 time_t min_registered
, max_registered
;
3271 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3272 const char *nickmask
;
3273 const char *hostmask
;
3274 const char *handlemask
;
3275 const char *emailmask
;
3278 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3280 struct discrim_apply_info
{
3281 struct nickserv_discrim
*discrim
;
3282 discrim_search_func func
;
3283 struct userNode
*source
;
3284 unsigned int matched
;
3287 static struct nickserv_discrim
*
3288 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3291 struct nickserv_discrim
*discrim
;
3293 discrim
= malloc(sizeof(*discrim
));
3294 memset(discrim
, 0, sizeof(*discrim
));
3295 discrim
->min_level
= 0;
3296 discrim
->max_level
= ~0;
3297 discrim
->limit
= 50;
3298 discrim
->min_registered
= 0;
3299 discrim
->max_registered
= INT_MAX
;
3300 discrim
->lastseen
= now
;
3302 for (i
=0; i
<argc
; i
++) {
3303 if (i
== argc
- 1) {
3304 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3307 if (!irccasecmp(argv
[i
], "limit")) {
3308 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3309 } else if (!irccasecmp(argv
[i
], "flags")) {
3310 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3311 } else if (!irccasecmp(argv
[i
], "registered")) {
3312 const char *cmp
= argv
[++i
];
3313 if (cmp
[0] == '<') {
3314 if (cmp
[1] == '=') {
3315 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3317 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3319 } else if (cmp
[0] == '=') {
3320 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3321 } else if (cmp
[0] == '>') {
3322 if (cmp
[1] == '=') {
3323 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3325 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3328 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3330 } else if (!irccasecmp(argv
[i
], "seen")) {
3331 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3332 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3333 discrim
->nickmask
= argv
[++i
];
3334 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3336 if (!irccasecmp(argv
[i
], "exact")) {
3337 if (i
== argc
- 1) {
3338 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3341 discrim
->hostmask_type
= EXACT
;
3342 } else if (!irccasecmp(argv
[i
], "subset")) {
3343 if (i
== argc
- 1) {
3344 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3347 discrim
->hostmask_type
= SUBSET
;
3348 } else if (!irccasecmp(argv
[i
], "superset")) {
3349 if (i
== argc
- 1) {
3350 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3353 discrim
->hostmask_type
= SUPERSET
;
3354 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3355 if (i
== argc
- 1) {
3356 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3359 discrim
->hostmask_type
= LASTQUIT
;
3362 discrim
->hostmask_type
= SUPERSET
;
3364 discrim
->hostmask
= argv
[++i
];
3365 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3366 if (!irccasecmp(argv
[++i
], "*")) {
3367 discrim
->handlemask
= 0;
3369 discrim
->handlemask
= argv
[i
];
3371 } else if (!irccasecmp(argv
[i
], "email")) {
3372 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3373 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3375 } else if (!irccasecmp(argv
[++i
], "*")) {
3376 discrim
->emailmask
= 0;
3378 discrim
->emailmask
= argv
[i
];
3380 } else if (!irccasecmp(argv
[i
], "access")) {
3381 const char *cmp
= argv
[++i
];
3382 if (cmp
[0] == '<') {
3383 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3384 if (cmp
[1] == '=') {
3385 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3387 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3389 } else if (cmp
[0] == '=') {
3390 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3391 } else if (cmp
[0] == '>') {
3392 if (cmp
[1] == '=') {
3393 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3395 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3398 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3401 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3412 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3414 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3415 || (discrim
->flags_off
& hi
->flags
)
3416 || (discrim
->min_registered
> hi
->registered
)
3417 || (discrim
->max_registered
< hi
->registered
)
3418 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3419 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3420 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3421 || (discrim
->min_level
> hi
->opserv_level
)
3422 || (discrim
->max_level
< hi
->opserv_level
)) {
3425 if (discrim
->hostmask
) {
3427 for (i
=0; i
<hi
->masks
->used
; i
++) {
3428 const char *mask
= hi
->masks
->list
[i
];
3429 if ((discrim
->hostmask_type
== SUBSET
)
3430 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3431 else if ((discrim
->hostmask_type
== EXACT
)
3432 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3433 else if ((discrim
->hostmask_type
== SUPERSET
)
3434 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3435 else if ((discrim
->hostmask_type
== LASTQUIT
)
3436 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3438 if (i
==hi
->masks
->used
) return 0;
3440 if (discrim
->nickmask
) {
3441 struct nick_info
*nick
= hi
->nicks
;
3443 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3446 if (!nick
) return 0;
3452 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3454 dict_iterator_t it
, next
;
3455 unsigned int matched
;
3457 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3458 it
&& (matched
< discrim
->limit
);
3460 next
= iter_next(it
);
3461 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3462 dsf(source
, iter_data(it
));
3470 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3472 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3476 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3481 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3483 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3484 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3488 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3490 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3491 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3492 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3493 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3494 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3498 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3500 struct handle_info_list hil
;
3501 struct helpfile_table tbl
;
3506 memset(&hil
, 0, sizeof(hil
));
3507 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3508 struct handle_info
*hi
= iter_data(it
);
3509 if (hi
->opserv_level
)
3510 handle_info_list_append(&hil
, hi
);
3512 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3513 tbl
.length
= hil
.used
+ 1;
3515 tbl
.flags
= TABLE_NO_FREE
;
3516 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3517 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3520 for (ii
= 0; ii
< hil
.used
; ) {
3521 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3522 ary
[0] = hil
.list
[ii
]->handle
;
3523 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3524 tbl
.contents
[++ii
] = ary
;
3526 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3527 reply("MSG_MATCH_COUNT", hil
.used
);
3528 for (ii
= 0; ii
< hil
.used
; ii
++)
3529 free(tbl
.contents
[ii
]);
3534 static NICKSERV_FUNC(cmd_search
)
3536 struct nickserv_discrim
*discrim
;
3537 discrim_search_func action
;
3538 struct svccmd
*subcmd
;
3539 unsigned int matches
;
3542 NICKSERV_MIN_PARMS(3);
3543 sprintf(buf
, "search %s", argv
[1]);
3544 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3545 if (!irccasecmp(argv
[1], "print"))
3546 action
= search_print_func
;
3547 else if (!irccasecmp(argv
[1], "count"))
3548 action
= search_count_func
;
3549 else if (!irccasecmp(argv
[1], "unregister"))
3550 action
= search_unregister_func
;
3552 reply("NSMSG_INVALID_ACTION", argv
[1]);
3556 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3559 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3563 if (action
== search_print_func
)
3564 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3565 else if (action
== search_count_func
)
3566 discrim
->limit
= INT_MAX
;
3568 matches
= nickserv_discrim_search(discrim
, action
, user
);
3571 reply("MSG_MATCH_COUNT", matches
);
3573 reply("MSG_NO_MATCHES");
3579 static MODCMD_FUNC(cmd_checkpass
)
3581 struct handle_info
*hi
;
3583 NICKSERV_MIN_PARMS(3);
3584 if (!(hi
= get_handle_info(argv
[1]))) {
3585 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3588 if (checkpass(argv
[2], hi
->passwd
))
3589 reply("CHECKPASS_YES");
3591 reply("CHECKPASS_NO");
3597 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3600 struct string_list
*masks
, *slist
;
3601 struct handle_info
*hi
;
3602 struct userNode
*authed_users
;
3603 struct userData
*channels
;
3604 unsigned long int id
;
3607 char *setter
, *note
;
3610 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3611 id
= str
? strtoul(str
, NULL
, 0) : 0;
3612 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3614 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3617 if ((hi
= get_handle_info(handle
))) {
3618 authed_users
= hi
->users
;
3619 channels
= hi
->channels
;
3621 hi
->channels
= NULL
;
3622 dict_remove(nickserv_handle_dict
, hi
->handle
);
3624 authed_users
= NULL
;
3627 hi
= register_handle(handle
, str
, id
);
3629 hi
->users
= authed_users
;
3630 while (authed_users
) {
3631 authed_users
->handle_info
= hi
;
3632 authed_users
= authed_users
->next_authed
;
3635 hi
->channels
= channels
;
3636 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3637 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3638 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3639 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3640 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3641 hi
->language
= language_find(str
? str
: "C");
3642 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3643 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3644 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3646 hi
->infoline
= strdup(str
);
3647 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3648 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3649 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3650 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3651 /* We want to read the nicks even if disable_nicks is set. This is so
3652 * that we don't lose the nick data entirely. */
3653 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3655 for (ii
=0; ii
<slist
->used
; ii
++)
3656 register_nick(slist
->list
[ii
], hi
);
3658 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3660 for (ii
=0; str
[ii
]; ii
++)
3661 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3663 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3664 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3665 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3666 hi
->announcements
= str
? str
[0] : '?';
3667 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3668 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3669 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3670 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3671 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3673 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3675 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3676 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3678 nickserv_set_email_addr(hi
, str
);
3679 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3681 hi
->epithet
= strdup(str
);
3682 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3684 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3685 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3686 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3687 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3688 if (setter
&& date
&& note
)
3690 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3695 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3697 hi
->fakehost
= strdup(str
);
3698 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3700 const char *data
, *type
, *expires
, *cookie_str
;
3701 struct handle_cookie
*cookie
;
3703 cookie
= calloc(1, sizeof(*cookie
));
3704 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3705 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3706 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3707 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3708 if (!type
|| !expires
|| !cookie_str
) {
3709 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3712 if (!irccasecmp(type
, KEY_ACTIVATION
))
3713 cookie
->type
= ACTIVATION
;
3714 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3715 cookie
->type
= PASSWORD_CHANGE
;
3716 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3717 cookie
->type
= EMAIL_CHANGE
;
3718 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3719 cookie
->type
= ALLOWAUTH
;
3721 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3724 cookie
->expires
= strtoul(expires
, NULL
, 0);
3725 if (cookie
->expires
< now
)
3728 cookie
->data
= strdup(data
);
3729 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3733 nickserv_bake_cookie(cookie
);
3735 nickserv_free_cookie(cookie
);
3740 nickserv_saxdb_read(dict_t db
) {
3742 struct record_data
*rd
;
3744 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3746 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3751 static NICKSERV_FUNC(cmd_mergedb
)
3753 struct timeval start
, stop
;
3756 NICKSERV_MIN_PARMS(2);
3757 gettimeofday(&start
, NULL
);
3758 if (!(db
= parse_database(argv
[1]))) {
3759 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3762 nickserv_saxdb_read(db
);
3764 gettimeofday(&stop
, NULL
);
3765 stop
.tv_sec
-= start
.tv_sec
;
3766 stop
.tv_usec
-= start
.tv_usec
;
3767 if (stop
.tv_usec
< 0) {
3769 stop
.tv_usec
+= 1000000;
3771 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3776 expire_handles(UNUSED_ARG(void *data
))
3778 dict_iterator_t it
, next
;
3780 struct handle_info
*hi
;
3782 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3783 next
= iter_next(it
);
3785 if ((hi
->opserv_level
> 0)
3787 || HANDLE_FLAGGED(hi
, FROZEN
)
3788 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3791 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3792 if ((now
- hi
->lastseen
) > expiry
) {
3793 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3794 nickserv_unregister_handle(hi
, NULL
, NULL
);
3798 if (nickserv_conf
.handle_expire_frequency
)
3799 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3803 nickserv_load_dict(const char *fname
)
3807 if (!(file
= fopen(fname
, "r"))) {
3808 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3811 while (!feof(file
)) {
3812 fgets(line
, sizeof(line
), file
);
3815 if (line
[strlen(line
)-1] == '\n')
3816 line
[strlen(line
)-1] = 0;
3817 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3820 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3823 static enum reclaim_action
3824 reclaim_action_from_string(const char *str
) {
3826 return RECLAIM_NONE
;
3827 else if (!irccasecmp(str
, "warn"))
3828 return RECLAIM_WARN
;
3829 else if (!irccasecmp(str
, "svsnick"))
3830 return RECLAIM_SVSNICK
;
3831 else if (!irccasecmp(str
, "kill"))
3832 return RECLAIM_KILL
;
3834 return RECLAIM_NONE
;
3838 nickserv_conf_read(void)
3840 dict_t conf_node
, child
;
3844 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3845 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3848 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3850 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3851 if (nickserv_conf
.valid_handle_regex_set
)
3852 regfree(&nickserv_conf
.valid_handle_regex
);
3854 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3855 nickserv_conf
.valid_handle_regex_set
= !err
;
3856 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3858 nickserv_conf
.valid_handle_regex_set
= 0;
3860 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3861 if (nickserv_conf
.valid_nick_regex_set
)
3862 regfree(&nickserv_conf
.valid_nick_regex
);
3864 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3865 nickserv_conf
.valid_nick_regex_set
= !err
;
3866 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3868 nickserv_conf
.valid_nick_regex_set
= 0;
3870 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3872 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3873 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3874 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3875 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3876 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3877 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3878 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3879 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3880 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3881 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3882 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3883 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3884 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3885 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3886 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3887 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3888 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3889 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3890 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3891 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3892 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3893 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3894 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3895 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3896 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3898 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3899 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3900 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3902 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3903 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3904 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3906 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3907 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3908 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3909 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3910 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3911 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3912 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3913 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3914 if (!nickserv_conf
.disable_nicks
) {
3915 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3916 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3917 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3918 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3919 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3920 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3921 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3922 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3924 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3925 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3926 const char *key
= iter_key(it
), *value
;
3930 if (!strncasecmp(key
, "uc_", 3))
3931 flag
= toupper(key
[3]);
3932 else if (!strncasecmp(key
, "lc_", 3))
3933 flag
= tolower(key
[3]);
3937 if ((pos
= handle_inverse_flags
[flag
])) {
3938 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3939 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3942 if (nickserv_conf
.weak_password_dict
)
3943 dict_delete(nickserv_conf
.weak_password_dict
);
3944 nickserv_conf
.weak_password_dict
= dict_new();
3945 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3946 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3947 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3948 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3950 nickserv_load_dict(str
);
3951 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3952 if (nickserv
&& str
)
3953 NickChange(nickserv
, str
, 0);
3954 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3955 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3956 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3957 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3958 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3959 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3960 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3961 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3962 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3963 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3964 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3965 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3966 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3967 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3968 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3969 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3970 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3971 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3972 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3973 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3975 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
3976 nickserv_conf
.auto_oper
= str
? str
: "";
3978 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
3979 nickserv_conf
.auto_admin
= str
? str
: "";
3981 str
= conf_get_data("server/network", RECDB_QSTRING
);
3982 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3983 if (!nickserv_conf
.auth_policer_params
) {
3984 nickserv_conf
.auth_policer_params
= policer_params_new();
3985 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3986 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3988 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3989 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3990 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3994 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3996 char newnick
[NICKLEN
+1];
4005 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4007 case RECLAIM_SVSNICK
:
4009 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4010 } while (GetUserH(newnick
));
4011 irc_svsnick(nickserv
, user
, newnick
);
4014 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4015 irc_kill(nickserv
, user
, msg
);
4021 nickserv_reclaim_p(void *data
) {
4022 struct userNode
*user
= data
;
4023 struct nick_info
*ni
= get_nick_info(user
->nick
);
4025 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4029 check_user_nick(struct userNode
*user
) {
4030 struct nick_info
*ni
;
4031 user
->modes
&= ~FLAGS_REGNICK
;
4032 if (!(ni
= get_nick_info(user
->nick
)))
4034 if (user
->handle_info
== ni
->owner
) {
4035 user
->modes
|= FLAGS_REGNICK
;
4039 if (nickserv_conf
.warn_nick_owned
)
4040 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4041 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4043 if (nickserv_conf
.auto_reclaim_delay
)
4044 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4046 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4051 handle_new_user(struct userNode
*user
)
4053 return check_user_nick(user
);
4057 handle_account(struct userNode
*user
, const char *stamp
)
4059 struct handle_info
*hi
;
4062 #ifdef WITH_PROTOCOL_P10
4063 time_t timestamp
= 0;
4065 colon
= strchr(stamp
, ':');
4066 if(colon
&& colon
[1])
4069 timestamp
= atoi(colon
+1);
4071 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4072 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4074 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
);
4078 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4079 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4083 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4086 set_user_handle_info(user
, hi
, 0);
4088 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4093 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4095 struct handle_info
*hi
;
4097 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4098 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4099 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4101 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4102 check_user_nick(user
);
4106 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4108 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4109 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4110 set_user_handle_info(user
, NULL
, 0);
4113 static struct modcmd
*
4114 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4116 if (min_level
> 0) {
4118 sprintf(buf
, "%u", min_level
);
4119 if (must_be_qualified
) {
4120 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4122 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4124 } else if (min_level
== 0) {
4125 if (must_be_qualified
) {
4126 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4128 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4131 if (must_be_qualified
) {
4132 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4134 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4140 nickserv_db_cleanup(void)
4142 unreg_del_user_func(nickserv_remove_user
);
4143 userList_clean(&curr_helpers
);
4144 policer_params_delete(nickserv_conf
.auth_policer_params
);
4145 dict_delete(nickserv_handle_dict
);
4146 dict_delete(nickserv_nick_dict
);
4147 dict_delete(nickserv_opt_dict
);
4148 dict_delete(nickserv_allow_auth_dict
);
4149 dict_delete(nickserv_email_dict
);
4150 dict_delete(nickserv_id_dict
);
4151 dict_delete(nickserv_conf
.weak_password_dict
);
4152 free(auth_func_list
);
4153 free(unreg_func_list
);
4155 free(allowauth_func_list
);
4156 free(handle_merge_func_list
);
4157 free(failpw_func_list
);
4158 if (nickserv_conf
.valid_handle_regex_set
)
4159 regfree(&nickserv_conf
.valid_handle_regex
);
4160 if (nickserv_conf
.valid_nick_regex_set
)
4161 regfree(&nickserv_conf
.valid_nick_regex
);
4165 init_nickserv(const char *nick
)
4168 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4169 reg_new_user_func(handle_new_user
);
4170 reg_nick_change_func(handle_nick_change
);
4171 reg_del_user_func(nickserv_remove_user
);
4172 reg_account_func(handle_account
);
4174 /* set up handle_inverse_flags */
4175 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4176 for (i
=0; handle_flags
[i
]; i
++) {
4177 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4178 flag_access_levels
[i
] = 0;
4181 conf_register_reload(nickserv_conf_read
);
4182 nickserv_opt_dict
= dict_new();
4183 nickserv_email_dict
= dict_new();
4184 dict_set_free_keys(nickserv_email_dict
, free
);
4185 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4187 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4188 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4189 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4190 * a big pain to disable since its nolonger in the config file. ) -Rubin
4192 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4193 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4194 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4195 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4196 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4197 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4198 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4199 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4200 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4201 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4202 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4203 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4204 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4205 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4206 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4207 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4208 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4209 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4210 if (!nickserv_conf
.disable_nicks
) {
4211 /* nick management commands */
4212 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4213 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4214 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4215 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4216 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4217 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4219 if (nickserv_conf
.email_enabled
) {
4220 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4221 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4222 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4223 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4224 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4225 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4227 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4228 /* miscellaneous commands */
4229 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4230 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4231 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4232 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4233 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4235 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4236 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4237 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4238 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4239 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4240 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4241 /* dict_insert(nickserv_opt_dict, "STYLE", opt_style); */
4242 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4243 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4244 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4245 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4246 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4247 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4248 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4249 if (nickserv_conf
.titlehost_suffix
) {
4250 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4251 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4253 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4254 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4255 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4257 nickserv_handle_dict
= dict_new();
4258 dict_set_free_keys(nickserv_handle_dict
, free
);
4259 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4261 nickserv_id_dict
= dict_new();
4262 dict_set_free_keys(nickserv_id_dict
, free
);
4264 nickserv_nick_dict
= dict_new();
4265 dict_set_free_data(nickserv_nick_dict
, free
);
4267 nickserv_allow_auth_dict
= dict_new();
4269 userList_init(&curr_helpers
);
4272 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4273 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4274 nickserv_service
= service_register(nickserv
);
4276 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4277 reg_exit_func(nickserv_db_cleanup
);
4278 if(nickserv_conf
.handle_expire_frequency
)
4279 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4280 message_register_table(msgtab
);