1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 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() */
30 #include <tre/regex.h>
32 #define NICKSERV_CONF_NAME "services/nickserv"
34 #define KEY_DISABLE_NICKS "disable_nicks"
35 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
36 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
37 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
38 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
39 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
40 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
41 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
42 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
43 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
44 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
45 #define KEY_VALID_FAKEHOST_REGEX "valid_fakehost_regex"
46 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
47 #define KEY_MODOPER_LEVEL "modoper_level"
48 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
49 #define KEY_SET_TITLE_LEVEL "set_title_level"
50 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
51 #define KEY_DENIED_FAKEHOST_WORDS "denied_fakehost_words"
52 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
53 #define KEY_AUTO_OPER "auto_oper"
54 #define KEY_AUTO_ADMIN "auto_admin"
55 #define KEY_FLAG_LEVELS "flag_levels"
56 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
57 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
58 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
59 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
60 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
61 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
62 #define KEY_DICT_FILE "dict_file"
63 #define KEY_NICK "nick"
64 #define KEY_LANGUAGE "language"
65 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
66 #define KEY_AUTOGAG_DURATION "autogag_duration"
67 #define KEY_AUTH_POLICER "auth_policer"
68 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
69 #define KEY_EMAIL_ENABLED "email_enabled"
70 #define KEY_EMAIL_REQUIRED "email_required"
71 #define KEY_SYNC_LOG "sync_log"
72 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
73 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
74 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
75 #define KEY_DEFAULT_STYLE "default_style"
78 #define KEY_PASSWD "passwd"
79 #define KEY_NICKS "nicks"
80 #define KEY_MASKS "masks"
81 #define KEY_IGNORES "ignores"
82 #define KEY_OPSERV_LEVEL "opserv_level"
83 #define KEY_FLAGS "flags"
84 #define KEY_REGISTER_ON "register"
85 #define KEY_LAST_SEEN "lastseen"
86 #define KEY_INFO "info"
87 #define KEY_USERLIST_STYLE "user_style"
88 #define KEY_SCREEN_WIDTH "screen_width"
89 #define KEY_LAST_AUTHED_HOST "last_authed_host"
90 #define KEY_LAST_QUIT_HOST "last_quit_host"
91 #define KEY_EMAIL_ADDR "email_addr"
92 #define KEY_COOKIE "cookie"
93 #define KEY_COOKIE_DATA "data"
94 #define KEY_COOKIE_TYPE "type"
95 #define KEY_COOKIE_EXPIRES "expires"
96 #define KEY_ACTIVATION "activation"
97 #define KEY_PASSWORD_CHANGE "password change"
98 #define KEY_EMAIL_CHANGE "email change"
99 #define KEY_ALLOWAUTH "allowauth"
100 #define KEY_EPITHET "epithet"
101 #define KEY_TABLE_WIDTH "table_width"
102 #define KEY_ANNOUNCEMENTS "announcements"
103 #define KEY_MAXLOGINS "maxlogins"
104 #define KEY_FAKEHOST "fakehost"
105 #define KEY_NOTE_NOTE "note"
106 #define KEY_NOTE_SETTER "setter"
107 #define KEY_NOTE_DATE "date"
110 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
112 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
113 #define OPTION_FUNC(NAME) int NAME(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
114 typedef OPTION_FUNC(option_func_t
);
116 DEFINE_LIST(handle_info_list
, struct handle_info
*);
118 #define NICKSERV_MIN_PARMS(N) do { \
120 reply("MSG_MISSING_PARAMS", argv[0]); \
121 svccmd_send_help_brief(user, nickserv, cmd); \
125 struct userNode
*nickserv
;
126 struct userList curr_helpers
;
127 const char *handle_flags
= HANDLE_FLAGS
;
129 extern struct string_list
*autojoin_channels
;
130 static struct module *nickserv_module
;
131 static struct service
*nickserv_service
;
132 static struct log_type
*NS_LOG
;
133 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
134 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
135 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
136 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
137 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
138 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
139 static char handle_inverse_flags
[256];
140 static unsigned int flag_access_levels
[32];
141 static const struct message_entry msgtab
[] = {
142 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
143 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
144 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
145 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
146 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
147 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
148 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
149 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
150 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
151 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
152 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
153 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
154 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
155 { "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." },
156 { "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." },
157 { "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." },
158 { "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." },
159 { "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." },
160 { "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." },
161 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
162 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
163 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
164 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
165 { "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." },
166 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
167 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
168 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
169 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
170 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
171 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
172 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
173 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
174 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
175 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
176 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
177 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
178 { "NSMSG_REGISTER_BAD_NICKMASK", "You must provide a hostmask, or online nick to generate one automatically. (or set a default hostmask in the config such as *@*)." },
179 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
180 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
181 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
182 { "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)" },
183 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
184 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
185 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
186 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
187 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
188 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
189 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
190 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
191 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
192 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
193 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
194 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
195 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
196 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
197 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
198 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
199 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
200 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
201 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
202 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
203 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
204 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
205 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
206 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
207 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
208 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
209 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
210 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
211 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
212 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
213 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
214 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
215 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
216 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
217 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
218 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
219 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
220 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
221 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
222 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
223 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
224 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
225 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
226 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
227 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
228 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
229 { "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)." },
230 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
231 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
232 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
233 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
234 { "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." },
235 { "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." },
236 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
237 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
238 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
239 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
240 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
241 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
242 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
243 { "NSMSG_PASS_SUCCESS", "Password changed." },
244 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
245 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
246 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
247 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
248 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
249 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
250 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
251 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
252 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
253 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
254 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
255 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
256 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
257 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
258 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
259 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
260 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
261 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
262 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
263 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
264 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
265 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
266 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
267 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
268 { "NSMSG_NO_ACCESS", "Access denied." },
269 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
270 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
271 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
272 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
273 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
274 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
275 { "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." },
276 { "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." },
277 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
278 { "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." },
279 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
280 { "NSMSG_SEARCH_MATCH", "Match: %s" },
281 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
282 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
283 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
284 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
285 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
286 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
287 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
288 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
289 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
290 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
291 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
292 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
293 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
294 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
295 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
296 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
297 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
298 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
299 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
300 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
301 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
302 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
303 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
304 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
305 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
306 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
307 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
308 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
309 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
310 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
311 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
312 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
313 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
314 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
316 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
317 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
319 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
320 { "NSEMAIL_ACTIVATION_BODY",
321 "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"
323 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
324 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
325 "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"
326 "/msg %3$s@%4$s AUTH %5$s your-password\n"
327 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
328 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\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_ACTIVATION_BODY_WEB",
333 "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"
335 "To verify your email address and complete the account registration, visit the following URL:\n"
336 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
338 "If you did NOT request this account, you do not need to do anything.\n"
339 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
340 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
341 { "NSEMAIL_PASSWORD_CHANGE_BODY",
342 "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"
343 "To complete the password change, log on to %1$s and type the following command:\n"
344 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
345 "If you did NOT request your password to be changed, you do not need to do anything.\n"
346 "Please contact the %1$s staff if you have questions." },
347 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
348 "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"
349 "To complete the password change, click the following URL:\n"
350 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
351 "If you did NOT request your password to be changed, you do not need to do anything.\n"
352 "Please contact the %1$s staff if you have questions." },
353 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
354 #ifdef stupid_verify_old_email
355 { "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." },
356 { "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." },
358 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
359 { "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." },
360 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
361 { "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." },
362 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
363 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
364 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
365 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
366 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
367 { "NSMSG_NOT_VALID_FAKEHOST_REGEX", "$b%s$b is not allowed by the admin, consult the valid vhost regex pattern in the config file under nickserv/valid_fakehost_regex." },
368 { "CHECKPASS_YES", "Yes." },
369 { "CHECKPASS_NO", "No." },
370 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
374 enum reclaim_action
{
380 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
381 static void nickserv_reclaim_p(void *data
);
384 unsigned int disable_nicks
: 1;
385 unsigned int valid_handle_regex_set
: 1;
386 unsigned int valid_nick_regex_set
: 1;
387 unsigned int valid_fakehost_regex_set
: 1;
388 unsigned int autogag_enabled
: 1;
389 unsigned int email_enabled
: 1;
390 unsigned int email_required
: 1;
391 unsigned int default_hostmask
: 1;
392 unsigned int warn_nick_owned
: 1;
393 unsigned int warn_clone_auth
: 1;
394 unsigned int sync_log
: 1;
395 unsigned long nicks_per_handle
;
396 unsigned long password_min_length
;
397 unsigned long password_min_digits
;
398 unsigned long password_min_upper
;
399 unsigned long password_min_lower
;
400 unsigned long db_backup_frequency
;
401 unsigned long handle_expire_frequency
;
402 unsigned long autogag_duration
;
403 unsigned long email_visible_level
;
404 unsigned long cookie_timeout
;
405 unsigned long handle_expire_delay
;
406 unsigned long nochan_handle_expire_delay
;
407 unsigned long modoper_level
;
408 unsigned long set_epithet_level
;
409 unsigned long set_title_level
;
410 unsigned long set_fakehost_level
;
411 unsigned long handles_per_email
;
412 unsigned long email_search_level
;
413 const char *network_name
;
414 const char *titlehost_suffix
;
415 regex_t valid_handle_regex
;
416 regex_t valid_nick_regex
;
417 regex_t valid_fakehost_regex
;
418 dict_t weak_password_dict
;
419 struct policer_params
*auth_policer_params
;
420 enum reclaim_action reclaim_action
;
421 enum reclaim_action auto_reclaim_action
;
422 unsigned long auto_reclaim_delay
;
423 unsigned char default_maxlogins
;
424 unsigned char hard_maxlogins
;
425 const char *auto_oper
;
426 const char *auto_admin
;
428 struct string_list
*denied_fakehost_words
;
431 /* We have 2^32 unique account IDs to use. */
432 unsigned long int highest_id
= 0;
435 canonicalize_hostmask(char *mask
)
437 char *out
= mask
, *temp
;
438 if ((temp
= strchr(mask
, '!'))) {
440 while (*temp
) *out
++ = *temp
++;
446 static struct handle_note
*
447 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
449 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
451 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
453 memcpy(note
->note
, text
, strlen(text
));
457 static struct handle_info
*
458 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
460 struct handle_info
*hi
;
462 #ifdef WITH_PROTOCOL_BAHAMUT
463 char id_base64
[IDLEN
+ 1];
466 /* Assign a unique account ID to the account; note that 0 is
467 an invalid account ID. 1 is therefore the first account ID. */
469 id
= 1 + highest_id
++;
471 /* Note: highest_id is and must always be the highest ID. */
472 if(id
> highest_id
) {
476 inttobase64(id_base64
, id
, IDLEN
);
478 /* Make sure an account with the same ID doesn't exist. If a
479 duplicate is found, log some details and assign a new one.
480 This should be impossible, but it never hurts to expect it. */
481 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
482 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
488 hi
= calloc(1, sizeof(*hi
));
489 hi
->userlist_style
= HI_DEFAULT_STYLE
;
490 hi
->announcements
= '?';
491 hi
->handle
= strdup(handle
);
492 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
494 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
496 #ifdef WITH_PROTOCOL_BAHAMUT
498 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
505 register_nick(const char *nick
, struct handle_info
*owner
)
507 struct nick_info
*ni
;
508 ni
= malloc(sizeof(struct nick_info
));
509 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
511 ni
->next
= owner
->nicks
;
513 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
517 delete_nick(struct nick_info
*ni
)
519 struct nick_info
*last
, *next
;
520 struct userNode
*user
;
521 /* Check to see if we should mark a user as unregistered. */
522 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
523 user
->modes
&= ~FLAGS_REGNICK
;
526 /* Remove ni from the nick_info linked list. */
527 if (ni
== ni
->owner
->nicks
) {
528 ni
->owner
->nicks
= ni
->next
;
530 last
= ni
->owner
->nicks
;
536 last
->next
= next
->next
;
538 dict_remove(nickserv_nick_dict
, ni
->nick
);
541 static unreg_func_t
*unreg_func_list
;
542 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
545 reg_unreg_func(unreg_func_t func
)
547 if (unreg_func_used
== unreg_func_size
) {
548 if (unreg_func_size
) {
549 unreg_func_size
<<= 1;
550 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
553 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
556 unreg_func_list
[unreg_func_used
++] = func
;
560 nickserv_free_cookie(void *data
)
562 struct handle_cookie
*cookie
= data
;
563 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
564 if (cookie
->data
) free(cookie
->data
);
569 free_handle_info(void *vhi
)
571 struct handle_info
*hi
= vhi
;
573 #ifdef WITH_PROTOCOL_BAHAMUT
576 inttobase64(id
, hi
->id
, IDLEN
);
577 dict_remove(nickserv_id_dict
, id
);
580 free_string_list(hi
->masks
);
581 free_string_list(hi
->ignores
);
585 delete_nick(hi
->nicks
);
591 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
592 nickserv_free_cookie(hi
->cookie
);
594 if (hi
->email_addr
) {
595 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
596 handle_info_list_remove(hil
, hi
);
598 dict_remove(nickserv_email_dict
, hi
->email_addr
);
603 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
606 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
609 struct userNode
*uNode
;
611 for (n
=0; n
<unreg_func_used
; n
++)
612 unreg_func_list
[n
](notify
, hi
);
614 if (nickserv_conf
.sync_log
) {
615 uNode
= GetUserH(hi
->users
->nick
);
619 set_user_handle_info(hi
->users
, NULL
, 0);
622 if (nickserv_conf
.disable_nicks
)
623 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
625 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
628 if (nickserv_conf
.sync_log
)
629 SyncLog("UNREGISTER %s", hi
->handle
);
631 dict_remove(nickserv_handle_dict
, hi
->handle
);
635 get_handle_info(const char *handle
)
637 return dict_find(nickserv_handle_dict
, handle
, 0);
641 get_nick_info(const char *nick
)
643 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
647 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
652 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
653 mn
= channel
->members
.list
[nn
];
654 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
661 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
662 if (!user
->handle_info
) {
664 send_message(user
, bot
, "MSG_AUTHENTICATE");
668 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
670 send_message(user
, bot
, "NSMSG_NO_ACCESS");
674 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
676 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
680 if (user
->handle_info
->opserv_level
< min_level
) {
682 send_message(user
, bot
, "NSMSG_NO_ACCESS");
690 is_valid_handle(const char *handle
)
692 struct userNode
*user
;
693 /* cant register a juped nick/service nick as handle, to prevent confusion */
694 user
= GetUserH(handle
);
695 if (user
&& IsLocal(user
))
697 /* check against maximum length */
698 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
700 /* for consistency, only allow account names that could be nicks */
701 if (!is_valid_nick(handle
))
703 /* disallow account names that look like bad words */
704 if (opserv_bad_channel(handle
))
706 /* test either regex or containing all valid chars */
707 if (nickserv_conf
.valid_handle_regex_set
) {
708 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
711 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
712 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
716 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
721 is_registerable_nick(const char *nick
)
723 /* make sure it could be used as an account name */
724 if (!is_valid_handle(nick
))
727 if (strlen(nick
) > NICKLEN
)
729 /* test either regex or as valid handle */
730 if (nickserv_conf
.valid_nick_regex_set
) {
731 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
734 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
735 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
741 /* this has been replaced with one in tools.c
744 is_valid_email_addr(const char *email)
746 return strchr(email, '@') != NULL;
752 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
754 if (hi
->email_addr
) {
755 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
756 return hi
->email_addr
;
766 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
768 struct handle_info
*hi
;
769 struct userNode
*target
;
773 if (!(hi
= get_handle_info(++name
))) {
774 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
779 if (!(target
= GetUserH(name
))) {
780 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
783 if (IsLocal(target
)) {
784 if (IsService(target
))
785 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
787 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
790 if (!(hi
= target
->handle_info
)) {
791 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
799 oper_outranks(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
) {
800 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
802 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
803 if ((user
->handle_info
->opserv_level
== 1000)
804 || (user
->handle_info
== hi
)
805 || ((user
->handle_info
->opserv_level
== 0)
806 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
807 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
811 reply("MSG_USER_OUTRANKED", hi
->handle
);
816 get_victim_oper(struct svccmd
*cmd
, struct userNode
*user
, const char *target
)
818 struct handle_info
*hi
;
819 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
821 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
822 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
825 return oper_outranks(cmd
, user
, hi
) ? hi
: NULL
;
829 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
833 /* If no hostmasks on the account, allow it. */
834 if (!hi
->masks
->used
)
836 /* If any hostmask matches, allow it. */
837 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
838 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
840 /* If they are allowauthed to this account, allow it (removing the aa). */
841 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
842 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
845 /* The user is not allowed to use this account. */
850 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
853 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
857 if (len
< nickserv_conf
.password_min_length
) {
859 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
862 if (!irccasecmp(pass
, handle
)) {
864 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
867 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
870 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
873 for (i
=0; i
<len
; i
++) {
874 if (isdigit(pass
[i
]))
876 if (isupper(pass
[i
]))
878 if (islower(pass
[i
]))
881 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
882 || (cnt_upper
< nickserv_conf
.password_min_upper
)
883 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
885 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
891 static auth_func_t
*auth_func_list
;
892 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
895 reg_auth_func(auth_func_t func
)
897 if (auth_func_used
== auth_func_size
) {
898 if (auth_func_size
) {
899 auth_func_size
<<= 1;
900 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
903 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
906 auth_func_list
[auth_func_used
++] = func
;
909 static handle_rename_func_t
*rf_list
;
910 static unsigned int rf_list_size
, rf_list_used
;
913 reg_handle_rename_func(handle_rename_func_t func
)
915 if (rf_list_used
== rf_list_size
) {
918 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
921 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
924 rf_list
[rf_list_used
++] = func
;
928 generate_fakehost(struct handle_info
*handle
)
930 extern const char *hidden_host_suffix
;
931 static char buffer
[HOSTLEN
+1];
933 if (!handle
->fakehost
) {
934 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
936 } else if (handle
->fakehost
[0] == '.') {
937 /* A leading dot indicates the stored value is actually a title. */
938 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
941 return handle
->fakehost
;
945 apply_fakehost(struct handle_info
*handle
)
947 struct userNode
*target
;
952 fake
= generate_fakehost(handle
);
953 for (target
= handle
->users
; target
; target
= target
->next_authed
)
954 assign_fakehost(target
, fake
, 1);
957 void send_func_list(struct userNode
*user
)
960 struct handle_info
*old_info
;
962 old_info
= user
->handle_info
;
964 for (n
=0; n
<auth_func_used
; n
++)
965 auth_func_list
[n
](user
, old_info
);
969 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
972 struct handle_info
*old_info
;
974 /* This can happen if somebody uses COOKIE while authed, or if
975 * they re-auth to their current handle (which is silly, but users
977 if (user
->handle_info
== hi
)
980 if (user
->handle_info
) {
981 struct userNode
*other
;
984 userList_remove(&curr_helpers
, user
);
986 /* remove from next_authed linked list */
987 if (user
->handle_info
->users
== user
) {
988 user
->handle_info
->users
= user
->next_authed
;
990 for (other
= user
->handle_info
->users
;
991 other
->next_authed
!= user
;
992 other
= other
->next_authed
) ;
993 other
->next_authed
= user
->next_authed
;
995 /* if nobody left on old handle, and they're not an oper, remove !god */
996 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
997 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
998 /* record them as being last seen at this time */
999 user
->handle_info
->lastseen
= now
;
1000 /* and record their hostmask */
1001 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
1003 old_info
= user
->handle_info
;
1004 user
->handle_info
= hi
;
1005 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1006 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1008 if (GetUserH(user
->nick
)) {
1009 for (n
=0; n
<auth_func_used
; n
++)
1010 auth_func_list
[n
](user
, old_info
);
1015 struct nick_info
*ni
;
1017 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1018 if (nickserv_conf
.warn_clone_auth
) {
1019 struct userNode
*other
;
1020 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1021 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1024 user
->next_authed
= hi
->users
;
1028 userList_append(&curr_helpers
, user
);
1030 if (hi
->fakehost
|| old_info
)
1034 #ifdef WITH_PROTOCOL_BAHAMUT
1035 /* Stamp users with their account ID. */
1037 inttobase64(id
, hi
->id
, IDLEN
);
1038 #elif WITH_PROTOCOL_P10
1039 /* Stamp users with their account name. */
1040 char *id
= hi
->handle
;
1042 const char *id
= "???";
1044 if (!nickserv_conf
.disable_nicks
) {
1045 struct nick_info
*ni
;
1046 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1047 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1048 user
->modes
|= FLAGS_REGNICK
;
1053 StampUser(user
, id
, hi
->registered
);
1056 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1057 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1059 /* We cannot clear the user's account ID, unfortunately. */
1060 user
->next_authed
= NULL
;
1064 static struct handle_info
*
1065 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1067 struct handle_info
*hi
;
1068 struct nick_info
*ni
;
1069 char crypted
[MD5_CRYPT_LENGTH
];
1071 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1072 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1076 if(strlen(handle
) > 15)
1078 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1082 if (!is_secure_password(handle
, passwd
, user
))
1085 cryptpass(passwd
, crypted
);
1086 hi
= register_handle(handle
, crypted
, 0);
1087 hi
->masks
= alloc_string_list(1);
1088 hi
->ignores
= alloc_string_list(1);
1090 hi
->language
= lang_C
;
1091 hi
->registered
= now
;
1093 hi
->flags
= HI_DEFAULT_FLAGS
;
1094 if (settee
&& !no_auth
)
1095 set_user_handle_info(settee
, hi
, 1);
1098 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1099 else if (nickserv_conf
.disable_nicks
)
1100 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1101 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1102 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1104 register_nick(user
->nick
, hi
);
1105 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1107 if (settee
&& (user
!= settee
))
1108 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1113 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1115 cookie
->hi
->cookie
= cookie
;
1116 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1119 /* Contributed by the great sneep of afternet ;) */
1120 /* Since this gets used in a URL, we want to avoid stuff that confuses
1121 * email clients such as ] and ?. a-z, 0-9 only.
1123 void genpass(char *str
, int len
)
1128 for(i
= 0; i
< len
; i
++)
1132 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1133 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1141 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1143 struct handle_cookie
*cookie
;
1144 char subject
[128], body
[4096], *misc
;
1145 const char *netname
, *fmt
;
1149 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1153 cookie
= calloc(1, sizeof(*cookie
));
1155 cookie
->type
= type
;
1156 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1158 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1159 /* Adding dedicated password gen function for more control -Rubin */
1160 genpass(cookie
->cookie
, 10);
1162 *inttobase64(cookie->cookie, rand(), 5);
1163 *inttobase64(cookie->cookie+5, rand(), 5);
1166 netname
= nickserv_conf
.network_name
;
1169 switch (cookie
->type
) {
1171 hi
->passwd
[0] = 0; /* invalidate password */
1172 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1173 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1174 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1177 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1179 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1181 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1184 case PASSWORD_CHANGE
:
1185 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1186 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1187 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1189 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1191 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1192 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1195 misc
= hi
->email_addr
;
1196 hi
->email_addr
= cookie
->data
;
1197 #ifdef stupid_verify_old_email
1199 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1200 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1201 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1202 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1203 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1204 sendmail(nickserv
, hi
, subject
, body
, 1);
1205 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1206 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1209 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1210 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1211 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1212 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1213 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1214 sendmail(nickserv
, hi
, subject
, body
, 1);
1216 #ifdef stupid_verify_old_email
1219 hi
->email_addr
= misc
;
1222 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1223 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1224 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1225 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1226 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1229 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1233 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1234 nickserv_bake_cookie(cookie
);
1238 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1240 cookie
->hi
->cookie
= NULL
;
1241 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1242 nickserv_free_cookie(cookie
);
1246 nickserv_free_email_addr(void *data
)
1248 handle_info_list_clean(data
);
1253 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1255 struct handle_info_list
*hil
;
1256 /* Remove from old handle_info_list ... */
1257 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1258 handle_info_list_remove(hil
, hi
);
1259 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1260 hi
->email_addr
= NULL
;
1262 /* Add to the new list.. */
1263 if (new_email_addr
) {
1264 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1265 hil
= calloc(1, sizeof(*hil
));
1266 hil
->tag
= strdup(new_email_addr
);
1267 handle_info_list_init(hil
);
1268 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1270 handle_info_list_append(hil
, hi
);
1271 hi
->email_addr
= hil
->tag
;
1275 static NICKSERV_FUNC(cmd_register
)
1278 struct handle_info
*hi
;
1279 const char *email_addr
, *password
;
1280 char syncpass
[MD5_CRYPT_LENGTH
];
1281 int no_auth
, weblink
;
1283 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1284 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1288 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1289 /* Require the first handle registered to belong to someone +o. */
1290 reply("NSMSG_REQUIRE_OPER");
1294 if (user
->handle_info
) {
1295 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1299 if (IsRegistering(user
)) {
1300 reply("NSMSG_ALREADY_REGISTERING");
1304 if (IsStamped(user
)) {
1305 /* Unauthenticated users might still have been stamped
1306 previously and could therefore have a hidden host;
1307 do not allow them to register a new account. */
1308 reply("NSMSG_STAMPED_REGISTER");
1312 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1314 if (!is_valid_handle(argv
[1])) {
1315 reply("NSMSG_BAD_HANDLE", argv
[1]);
1320 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1321 struct handle_info_list
*hil
;
1324 /* Remember email address. */
1325 email_addr
= argv
[3];
1327 /* Check that the email address looks valid.. */
1328 if (!valid_email(email_addr
)) {
1329 reply("NSMSG_BAD_EMAIL_ADDR");
1333 /* .. and that we are allowed to send to it. */
1334 if ((str
= sendmail_prohibited_address(email_addr
))) {
1335 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1339 /* If we do email verify, make sure we don't spam the address. */
1340 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1342 for (nn
=0; nn
<hil
->used
; nn
++) {
1343 if (hil
->list
[nn
]->cookie
) {
1344 reply("NSMSG_EMAIL_UNACTIVATED");
1348 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1349 reply("NSMSG_EMAIL_OVERUSED");
1362 /* Webregister hack - send URL instead of IRC cookie
1365 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1369 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1371 /* Add any masks they should get. */
1372 if (nickserv_conf
.default_hostmask
) {
1373 string_list_append(hi
->masks
, strdup("*@*"));
1375 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1376 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1377 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1380 /* If they're the first to register, give them level 1000. */
1381 if (dict_size(nickserv_handle_dict
) == 1) {
1382 hi
->opserv_level
= 1000;
1383 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1386 /* Set their email address. */
1388 nickserv_set_email_addr(hi
, email_addr
);
1390 /* If they need to do email verification, tell them. */
1392 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1394 /* Set registering flag.. */
1395 user
->modes
|= FLAGS_REGISTERING
;
1397 if (nickserv_conf
.sync_log
) {
1398 cryptpass(password
, syncpass
);
1400 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1401 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1404 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1407 /* this wont work if email is required .. */
1408 process_adduser_pending(user
);
1413 static NICKSERV_FUNC(cmd_oregister
)
1415 struct userNode
*settee
= NULL
;
1416 struct handle_info
*hi
;
1417 char* account
= NULL
;
1423 NICKSERV_MIN_PARMS(3);
1427 if (nickserv_conf
.email_required
) {
1428 NICKSERV_MIN_PARMS(4);
1430 if (argc
>= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1431 if (strchr(argv
[4], '@') || argc
>= 6) /* If @, its mask not nick */
1441 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1442 if (strchr(argv
[3], '@') || argc
>= 5) /* If @, its mask not nick */
1451 /* If they passed a nick, look for that user.. */
1452 if (nick
&& !(settee
= GetUserH(nick
))) {
1453 reply("MSG_NICK_UNKNOWN", argv
[4]);
1456 /* If the setee is already authed, we cant add a 2nd account for them.. */
1457 if (settee
&& settee
->handle_info
) {
1458 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1461 /* If there is no default mask in the conf, and they didn't pass a mask,
1462 * but we did find a user by nick, generate the mask */
1464 if (nickserv_conf
.default_hostmask
)
1467 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1469 reply("NSMSG_REGISTER_BAD_NICKMASK");
1474 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1475 return 0; /* error reply handled by above */
1478 nickserv_set_email_addr(hi
, email
);
1481 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1482 string_list_append(hi
->masks
, mask_canonicalized
);
1485 if (nickserv_conf
.sync_log
)
1486 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1491 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1494 struct userNode
*target
;
1495 char *new_mask
= strdup(pretty_mask(mask
));
1496 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1497 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1498 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1503 string_list_append(hi
->ignores
, new_mask
);
1504 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1506 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1507 irc_silence(target
, new_mask
, 1);
1512 static NICKSERV_FUNC(cmd_addignore
)
1514 NICKSERV_MIN_PARMS(2);
1516 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1519 static NICKSERV_FUNC(cmd_oaddignore
)
1521 struct handle_info
*hi
;
1523 NICKSERV_MIN_PARMS(3);
1524 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1527 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1531 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1534 struct userNode
*target
;
1535 char *pmask
= strdup(pretty_mask(del_mask
));
1536 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1537 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1538 char *old_mask
= hi
->ignores
->list
[i
];
1539 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1540 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1541 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1542 irc_silence(target
, old_mask
, 0);
1549 reply("NSMSG_DELMASK_NOT_FOUND");
1553 static NICKSERV_FUNC(cmd_delignore
)
1555 NICKSERV_MIN_PARMS(2);
1556 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1559 static NICKSERV_FUNC(cmd_odelignore
)
1561 struct handle_info
*hi
;
1562 NICKSERV_MIN_PARMS(3);
1563 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1565 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1568 static NICKSERV_FUNC(cmd_handleinfo
)
1571 unsigned int i
, pos
=0, herelen
;
1572 struct userNode
*target
, *next_un
;
1573 struct handle_info
*hi
;
1574 const char *nsmsg_none
;
1577 if (!(hi
= user
->handle_info
)) {
1578 reply("NSMSG_MUST_AUTH");
1581 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1585 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1586 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1588 #ifdef WITH_PROTOCOL_BAHAMUT
1589 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1591 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1594 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1595 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1597 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1600 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1601 if (HANDLE_FLAGGED(hi
, FROZEN
))
1602 reply("NSMSG_HANDLEINFO_VACATION");
1604 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1605 struct do_not_register
*dnr
;
1606 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1607 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1608 if (!oper_outranks(cmd
, user
, hi
))
1610 } else if (hi
!= user
->handle_info
) {
1611 reply("NSMSG_HANDLEINFO_END");
1615 if (nickserv_conf
.email_enabled
)
1616 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1620 switch (hi
->cookie
->type
) {
1621 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1622 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1623 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1624 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1625 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1631 unsigned long flen
= 1;
1632 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1634 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1635 if (hi
->flags
& 1 << i
)
1636 flags
[flen
++] = handle_flags
[i
];
1638 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1640 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1643 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1644 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1645 || (hi
->opserv_level
> 0)) {
1646 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1649 if (IsHelping(user
) || IsOper(user
))
1654 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1655 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1660 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1662 if (hi
->last_quit_host
[0])
1663 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1665 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1667 if (nickserv_conf
.disable_nicks
) {
1668 /* nicks disabled; don't show anything about registered nicks */
1669 } else if (hi
->nicks
) {
1670 struct nick_info
*ni
, *next_ni
;
1671 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1672 herelen
= strlen(ni
->nick
);
1673 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1675 goto print_nicks_buff
;
1679 memcpy(buff
+pos
, ni
->nick
, herelen
);
1680 pos
+= herelen
; buff
[pos
++] = ' ';
1684 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1689 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1692 if (hi
->masks
->used
) {
1693 for (i
=0; i
< hi
->masks
->used
; i
++) {
1694 herelen
= strlen(hi
->masks
->list
[i
]);
1695 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1697 goto print_mask_buff
;
1699 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1700 pos
+= herelen
; buff
[pos
++] = ' ';
1701 if (i
+1 == hi
->masks
->used
) {
1704 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1709 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1712 if (hi
->ignores
->used
) {
1713 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1714 herelen
= strlen(hi
->ignores
->list
[i
]);
1715 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1717 goto print_ignore_buff
;
1719 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1720 pos
+= herelen
; buff
[pos
++] = ' ';
1721 if (i
+1 == hi
->ignores
->used
) {
1724 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1729 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1733 struct userData
*channel
, *next
;
1736 for (channel
= hi
->channels
; channel
; channel
= next
) {
1737 next
= channel
->u_next
;
1738 name
= channel
->channel
->channel
->name
;
1739 herelen
= strlen(name
);
1740 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1742 goto print_chans_buff
;
1744 if (IsUserSuspended(channel
))
1746 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1750 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1755 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1758 for (target
= hi
->users
; target
; target
= next_un
) {
1759 herelen
= strlen(target
->nick
);
1760 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1762 goto print_cnick_buff
;
1764 next_un
= target
->next_authed
;
1766 memcpy(buff
+pos
, target
->nick
, herelen
);
1767 pos
+= herelen
; buff
[pos
++] = ' ';
1771 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1776 reply("NSMSG_HANDLEINFO_END");
1780 static NICKSERV_FUNC(cmd_userinfo
)
1782 struct userNode
*target
;
1784 NICKSERV_MIN_PARMS(2);
1785 if (!(target
= GetUserH(argv
[1]))) {
1786 reply("MSG_NICK_UNKNOWN", argv
[1]);
1789 if (target
->handle_info
)
1790 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1792 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1796 static NICKSERV_FUNC(cmd_nickinfo
)
1798 struct nick_info
*ni
;
1800 NICKSERV_MIN_PARMS(2);
1801 if (!(ni
= get_nick_info(argv
[1]))) {
1802 reply("MSG_NICK_UNKNOWN", argv
[1]);
1805 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1809 static NICKSERV_FUNC(cmd_rename_handle
)
1811 struct handle_info
*hi
;
1812 struct userNode
*uNode
;
1813 char msgbuf
[MAXLEN
], *old_handle
;
1816 NICKSERV_MIN_PARMS(3);
1817 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1819 if (!is_valid_handle(argv
[2])) {
1820 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1823 if (get_handle_info(argv
[2])) {
1824 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1827 if(strlen(argv
[2]) > 15)
1829 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1833 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1834 hi
->handle
= strdup(argv
[2]);
1835 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1836 for (nn
=0; nn
<rf_list_used
; nn
++)
1837 rf_list
[nn
](hi
, old_handle
);
1838 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1841 if (nickserv_conf
.sync_log
) {
1842 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1843 irc_rename(uNode
, hi
->handle
);
1845 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1848 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1849 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1854 static failpw_func_t
*failpw_func_list
;
1855 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1858 reg_failpw_func(failpw_func_t func
)
1860 if (failpw_func_used
== failpw_func_size
) {
1861 if (failpw_func_size
) {
1862 failpw_func_size
<<= 1;
1863 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1865 failpw_func_size
= 8;
1866 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1869 failpw_func_list
[failpw_func_used
++] = func
;
1873 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1875 * called by nefariouses enhanced AC login-on-connect code
1878 struct handle_info
*loc_auth(char *handle
, char *password
)
1880 int pw_arg
, used
, maxlogins
;
1883 struct handle_info
*hi
;
1884 struct userNode
*other
;
1886 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1892 /* We don't know the users hostname, or anything because they
1893 * havn't registered yet. So we can only allow LOC if your
1894 * account has *@* as a hostmask.
1896 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1898 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1907 /* Responses from here on look up the language used by the handle they asked about. */
1908 if (!checkpass(password
, hi
->passwd
)) {
1911 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1914 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1915 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1916 if (++used
>= maxlogins
) {
1923 static NICKSERV_FUNC(cmd_auth
)
1925 int pw_arg
, used
, maxlogins
;
1926 struct handle_info
*hi
;
1928 struct userNode
*other
;
1930 if (user
->handle_info
) {
1931 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1934 if (IsStamped(user
)) {
1935 /* Unauthenticated users might still have been stamped
1936 previously and could therefore have a hidden host;
1937 do not allow them to authenticate. */
1938 reply("NSMSG_STAMPED_AUTH");
1942 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1944 } else if (argc
== 2) {
1945 if (nickserv_conf
.disable_nicks
) {
1946 if (!(hi
= get_handle_info(user
->nick
))) {
1947 reply("NSMSG_HANDLE_NOT_FOUND");
1951 /* try to look up their handle from their nick */
1952 struct nick_info
*ni
;
1953 ni
= get_nick_info(user
->nick
);
1955 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1962 reply("MSG_MISSING_PARAMS", argv
[0]);
1963 svccmd_send_help_brief(user
, nickserv
, cmd
);
1967 reply("NSMSG_HANDLE_NOT_FOUND");
1970 /* Responses from here on look up the language used by the handle they asked about. */
1971 passwd
= argv
[pw_arg
];
1972 if (!valid_user_for(user
, hi
)) {
1973 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1974 send_message_type(4, user
, cmd
->parent
->bot
,
1975 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1978 send_message_type(4, user
, cmd
->parent
->bot
,
1979 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1981 argv
[pw_arg
] = "BADMASK";
1984 if (!checkpass(passwd
, hi
->passwd
)) {
1986 send_message_type(4, user
, cmd
->parent
->bot
,
1987 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1988 argv
[pw_arg
] = "BADPASS";
1989 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1990 if (nickserv_conf
.autogag_enabled
) {
1991 if (!user
->auth_policer
.params
) {
1992 user
->auth_policer
.last_req
= now
;
1993 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1995 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1997 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1998 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1999 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2001 argv
[pw_arg
] = "GAGGED";
2006 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2007 send_message_type(4, user
, cmd
->parent
->bot
,
2008 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2009 argv
[pw_arg
] = "SUSPENDED";
2012 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2013 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2014 if (++used
>= maxlogins
) {
2015 send_message_type(4, user
, cmd
->parent
->bot
,
2016 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2018 argv
[pw_arg
] = "MAXLOGINS";
2023 set_user_handle_info(user
, hi
, 1);
2024 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2025 reply("NSMSG_PLEASE_SET_EMAIL");
2026 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2027 reply("NSMSG_WEAK_PASSWORD");
2028 if (hi
->passwd
[0] != '$')
2029 cryptpass(passwd
, hi
->passwd
);
2031 /* If a channel was waiting for this user to auth,
2032 * finish adding them */
2033 process_adduser_pending(user
);
2035 reply("NSMSG_AUTH_SUCCESS");
2038 /* Set +x if autohide is on */
2039 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2040 irc_umode(user
, "+x");
2042 if(!IsOper(user
)) /* If they arnt already opered.. */
2044 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2045 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2047 irc_umode(user
,nickserv_conf
.auto_admin
);
2048 reply("NSMSG_AUTO_OPER_ADMIN");
2050 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2052 irc_umode(user
,nickserv_conf
.auto_oper
);
2053 reply("NSMSG_AUTO_OPER");
2057 /* Wipe out the pass for the logs */
2058 argv
[pw_arg
] = "****";
2062 static allowauth_func_t
*allowauth_func_list
;
2063 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2066 reg_allowauth_func(allowauth_func_t func
)
2068 if (allowauth_func_used
== allowauth_func_size
) {
2069 if (allowauth_func_size
) {
2070 allowauth_func_size
<<= 1;
2071 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2073 allowauth_func_size
= 8;
2074 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2077 allowauth_func_list
[allowauth_func_used
++] = func
;
2080 static NICKSERV_FUNC(cmd_allowauth
)
2082 struct userNode
*target
;
2083 struct handle_info
*hi
;
2086 NICKSERV_MIN_PARMS(2);
2087 if (!(target
= GetUserH(argv
[1]))) {
2088 reply("MSG_NICK_UNKNOWN", argv
[1]);
2091 if (target
->handle_info
) {
2092 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2095 if (IsStamped(target
)) {
2096 /* Unauthenticated users might still have been stamped
2097 previously and could therefore have a hidden host;
2098 do not allow them to authenticate to an account. */
2099 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2104 else if (!(hi
= get_handle_info(argv
[2]))) {
2105 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2109 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2110 reply("MSG_USER_OUTRANKED", hi
->handle
);
2113 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2114 || (hi
->opserv_level
> 0))
2115 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2116 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2119 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2120 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2121 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2122 if (nickserv_conf
.email_enabled
)
2123 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2125 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2126 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2128 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2130 for (n
=0; n
<allowauth_func_used
; n
++)
2131 allowauth_func_list
[n
](user
, target
, hi
);
2135 static NICKSERV_FUNC(cmd_authcookie
)
2137 struct handle_info
*hi
;
2139 NICKSERV_MIN_PARMS(2);
2140 if (user
->handle_info
) {
2141 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2144 if (IsStamped(user
)) {
2145 /* Unauthenticated users might still have been stamped
2146 previously and could therefore have a hidden host;
2147 do not allow them to authenticate to an account. */
2148 reply("NSMSG_STAMPED_AUTHCOOKIE");
2151 if (!(hi
= get_handle_info(argv
[1]))) {
2152 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2155 if (!hi
->email_addr
) {
2156 reply("MSG_SET_EMAIL_ADDR");
2159 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2163 static NICKSERV_FUNC(cmd_delcookie
)
2165 struct handle_info
*hi
;
2167 hi
= user
->handle_info
;
2169 reply("NSMSG_NO_COOKIE");
2172 switch (hi
->cookie
->type
) {
2175 reply("NSMSG_MUST_TIME_OUT");
2178 nickserv_eat_cookie(hi
->cookie
);
2179 reply("NSMSG_ATE_COOKIE");
2185 static NICKSERV_FUNC(cmd_odelcookie
)
2187 struct handle_info
*hi
;
2189 NICKSERV_MIN_PARMS(2);
2191 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2195 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2199 nickserv_eat_cookie(hi
->cookie
);
2200 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2205 static NICKSERV_FUNC(cmd_resetpass
)
2207 struct handle_info
*hi
;
2208 char crypted
[MD5_CRYPT_LENGTH
];
2211 NICKSERV_MIN_PARMS(3);
2212 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2216 if (user
->handle_info
) {
2217 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2220 if (IsStamped(user
)) {
2221 /* Unauthenticated users might still have been stamped
2222 previously and could therefore have a hidden host;
2223 do not allow them to activate an account. */
2224 reply("NSMSG_STAMPED_RESETPASS");
2227 if (!(hi
= get_handle_info(argv
[1]))) {
2228 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2231 if (!hi
->email_addr
) {
2232 reply("MSG_SET_EMAIL_ADDR");
2235 cryptpass(argv
[2], crypted
);
2237 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2241 static NICKSERV_FUNC(cmd_cookie
)
2243 struct handle_info
*hi
;
2246 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2249 NICKSERV_MIN_PARMS(3);
2250 if (!(hi
= get_handle_info(argv
[1]))) {
2251 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2257 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2258 reply("NSMSG_HANDLE_SUSPENDED");
2263 reply("NSMSG_NO_COOKIE");
2267 /* Check validity of operation before comparing cookie to
2268 * prohibit guessing by authed users. */
2269 if (user
->handle_info
2270 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2271 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2272 reply("NSMSG_CANNOT_COOKIE");
2276 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2277 reply("NSMSG_BAD_COOKIE");
2281 switch (hi
->cookie
->type
) {
2283 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2284 set_user_handle_info(user
, hi
, 1);
2285 reply("NSMSG_HANDLE_ACTIVATED");
2286 if (nickserv_conf
.sync_log
)
2287 SyncLog("ACCOUNTACC %s", hi
->handle
);
2289 case PASSWORD_CHANGE
:
2290 set_user_handle_info(user
, hi
, 1);
2291 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2292 reply("NSMSG_PASSWORD_CHANGED");
2293 if (nickserv_conf
.sync_log
)
2294 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2297 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2299 * This should only happen if an OREGISTER was sent. Require
2300 * email must be enabled! - SiRVulcaN
2302 if (nickserv_conf
.sync_log
)
2303 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2305 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2306 reply("NSMSG_EMAIL_CHANGED");
2307 if (nickserv_conf
.sync_log
)
2308 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2311 set_user_handle_info(user
, hi
, 1);
2312 reply("NSMSG_AUTH_SUCCESS");
2315 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2316 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2320 nickserv_eat_cookie(hi
->cookie
);
2322 process_adduser_pending(user
);
2327 static NICKSERV_FUNC(cmd_oregnick
) {
2329 struct handle_info
*target
;
2330 struct nick_info
*ni
;
2332 NICKSERV_MIN_PARMS(3);
2333 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2336 if (!is_registerable_nick(nick
)) {
2337 reply("NSMSG_BAD_NICK", nick
);
2340 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2342 reply("NSMSG_NICK_EXISTS", nick
);
2345 register_nick(nick
, target
);
2346 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2350 static NICKSERV_FUNC(cmd_regnick
) {
2352 struct nick_info
*ni
;
2354 if (!is_registerable_nick(user
->nick
)) {
2355 reply("NSMSG_BAD_NICK", user
->nick
);
2358 /* count their nicks, see if it's too many */
2359 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2360 if (n
>= nickserv_conf
.nicks_per_handle
) {
2361 reply("NSMSG_TOO_MANY_NICKS");
2364 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2366 reply("NSMSG_NICK_EXISTS", user
->nick
);
2369 register_nick(user
->nick
, user
->handle_info
);
2370 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2374 static NICKSERV_FUNC(cmd_pass
)
2376 struct handle_info
*hi
;
2377 const char *old_pass
, *new_pass
;
2379 NICKSERV_MIN_PARMS(3);
2380 hi
= user
->handle_info
;
2384 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2385 if (!checkpass(old_pass
, hi
->passwd
)) {
2386 argv
[1] = "BADPASS";
2387 reply("NSMSG_PASSWORD_INVALID");
2390 cryptpass(new_pass
, hi
->passwd
);
2391 if (nickserv_conf
.sync_log
)
2392 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2394 reply("NSMSG_PASS_SUCCESS");
2399 nickserv_addmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2402 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2403 for (i
=0; i
<hi
->masks
->used
; i
++) {
2404 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2405 reply("NSMSG_ADDMASK_ALREADY", new_mask
);
2410 string_list_append(hi
->masks
, new_mask
);
2411 reply("NSMSG_ADDMASK_SUCCESS", new_mask
);
2415 static NICKSERV_FUNC(cmd_addmask
)
2418 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2419 int res
= nickserv_addmask(cmd
, user
, user
->handle_info
, mask
);
2423 if (!is_gline(argv
[1])) {
2424 reply("NSMSG_MASK_INVALID", argv
[1]);
2427 return nickserv_addmask(cmd
, user
, user
->handle_info
, argv
[1]);
2431 static NICKSERV_FUNC(cmd_oaddmask
)
2433 struct handle_info
*hi
;
2435 NICKSERV_MIN_PARMS(3);
2436 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2438 return nickserv_addmask(cmd
, user
, hi
, argv
[2]);
2442 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2445 for (i
=0; i
<hi
->masks
->used
; i
++) {
2446 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2447 char *old_mask
= hi
->masks
->list
[i
];
2448 if (hi
->masks
->used
== 1) {
2449 reply("NSMSG_DELMASK_NOTLAST");
2452 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2453 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2458 reply("NSMSG_DELMASK_NOT_FOUND");
2462 static NICKSERV_FUNC(cmd_delmask
)
2464 NICKSERV_MIN_PARMS(2);
2465 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1]);
2468 static NICKSERV_FUNC(cmd_odelmask
)
2470 struct handle_info
*hi
;
2471 NICKSERV_MIN_PARMS(3);
2472 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2474 return nickserv_delmask(cmd
, user
, hi
, argv
[2]);
2478 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2479 unsigned int nn
, add
= 1, pos
;
2480 unsigned long added
, removed
, flag
;
2482 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2484 case '+': add
= 1; break;
2485 case '-': add
= 0; break;
2487 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2488 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2491 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2492 /* cheesy avoidance of looking up the flag name.. */
2493 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2496 flag
= 1 << (pos
- 1);
2498 added
|= flag
, removed
&= ~flag
;
2500 removed
|= flag
, added
&= ~flag
;
2505 *premoved
= removed
;
2510 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2512 unsigned long before
, after
, added
, removed
;
2513 struct userNode
*uNode
;
2515 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2516 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2518 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2519 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2521 /* Strip helping flag if they're only a support helper and not
2522 * currently in #support. */
2523 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2524 struct channelList
*schannels
;
2526 schannels
= chanserv_support_channels();
2527 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2528 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2529 if (GetUserMode(schannels
->list
[ii
], uNode
))
2531 if (ii
< schannels
->used
)
2535 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2538 if (after
&& !before
) {
2539 /* Add user to current helper list. */
2540 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2541 userList_append(&curr_helpers
, uNode
);
2542 } else if (!after
&& before
) {
2543 /* Remove user from current helper list. */
2544 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2545 userList_remove(&curr_helpers
, uNode
);
2552 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2556 char *set_display
[] = {
2557 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2558 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2559 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2562 reply("NSMSG_SETTING_LIST");
2563 reply("NSMSG_SETTING_LIST_HEADER");
2565 /* Do this so options are presented in a consistent order. */
2566 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2567 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2568 opt(cmd
, user
, hi
, override
, 0, NULL
);
2569 reply("NSMSG_SETTING_LIST_END");
2572 static NICKSERV_FUNC(cmd_set
)
2574 struct handle_info
*hi
;
2577 hi
= user
->handle_info
;
2579 set_list(cmd
, user
, hi
, 0);
2582 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2583 reply("NSMSG_INVALID_OPTION", argv
[1]);
2586 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2589 static NICKSERV_FUNC(cmd_oset
)
2591 struct handle_info
*hi
;
2594 NICKSERV_MIN_PARMS(2);
2596 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2600 set_list(cmd
, user
, hi
, 0);
2604 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2605 reply("NSMSG_INVALID_OPTION", argv
[2]);
2609 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
2612 static OPTION_FUNC(opt_info
)
2616 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2618 hi
->infoline
= NULL
;
2620 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2624 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2625 reply("NSMSG_SET_INFO", info
);
2629 static OPTION_FUNC(opt_width
)
2632 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2634 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2635 hi
->screen_width
= MIN_LINE_SIZE
;
2636 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2637 hi
->screen_width
= MAX_LINE_SIZE
;
2639 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
2643 static OPTION_FUNC(opt_tablewidth
)
2646 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2648 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2649 hi
->table_width
= MIN_LINE_SIZE
;
2650 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2651 hi
->table_width
= MAX_LINE_SIZE
;
2653 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2657 static OPTION_FUNC(opt_color
)
2660 if (enabled_string(argv
[1]))
2661 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2662 else if (disabled_string(argv
[1]))
2663 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2665 reply("MSG_INVALID_BINARY", argv
[1]);
2670 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2674 static OPTION_FUNC(opt_privmsg
)
2677 if (enabled_string(argv
[1]))
2678 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2679 else if (disabled_string(argv
[1]))
2680 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2682 reply("MSG_INVALID_BINARY", argv
[1]);
2687 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2691 static OPTION_FUNC(opt_autohide
)
2694 if (enabled_string(argv
[1]))
2695 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2696 else if (disabled_string(argv
[1]))
2697 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2699 reply("MSG_INVALID_BINARY", argv
[1]);
2704 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2708 static OPTION_FUNC(opt_style
)
2713 if (!irccasecmp(argv
[1], "Clean"))
2714 hi
->userlist_style
= HI_STYLE_CLEAN
;
2715 else if (!irccasecmp(argv
[1], "Advanced"))
2716 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2717 else if (!irccasecmp(argv
[1], "Classic"))
2718 hi
->userlist_style
= HI_STYLE_CLASSIC
;
2719 else /* Default to normal */
2720 hi
->userlist_style
= HI_STYLE_NORMAL
;
2721 } /* TODO: give error if unknow style is chosen */
2723 switch (hi
->userlist_style
) {
2724 case HI_STYLE_ADVANCED
:
2727 case HI_STYLE_CLASSIC
:
2730 case HI_STYLE_CLEAN
:
2733 case HI_STYLE_NORMAL
:
2738 reply("NSMSG_SET_STYLE", style
);
2742 static OPTION_FUNC(opt_announcements
)
2747 if (enabled_string(argv
[1]))
2748 hi
->announcements
= 'y';
2749 else if (disabled_string(argv
[1]))
2750 hi
->announcements
= 'n';
2751 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2752 hi
->announcements
= '?';
2754 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
2759 switch (hi
->announcements
) {
2760 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2761 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2762 case '?': choice
= "default"; break;
2763 default: choice
= "unknown"; break;
2765 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
2769 static OPTION_FUNC(opt_password
)
2772 reply("NSMSG_USE_CMD_PASS");
2777 cryptpass(argv
[1], hi
->passwd
);
2779 if (nickserv_conf
.sync_log
)
2780 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2782 reply("NSMSG_SET_PASSWORD", "***");
2786 static OPTION_FUNC(opt_flags
)
2789 unsigned int ii
, flen
;
2792 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2797 nickserv_apply_flags(user
, hi
, argv
[1]);
2799 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2800 if (hi
->flags
& (1 << ii
))
2801 flags
[flen
++] = handle_flags
[ii
];
2804 reply("NSMSG_SET_FLAGS", flags
);
2806 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2810 static OPTION_FUNC(opt_email
)
2814 if (!valid_email(argv
[1])) {
2815 reply("NSMSG_BAD_EMAIL_ADDR");
2818 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2819 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2822 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2823 reply("NSMSG_EMAIL_SAME");
2825 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2827 nickserv_set_email_addr(hi
, argv
[1]);
2829 nickserv_eat_cookie(hi
->cookie
);
2830 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2833 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2837 static OPTION_FUNC(opt_maxlogins
)
2839 unsigned char maxlogins
;
2841 maxlogins
= strtoul(argv
[1], NULL
, 0);
2842 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2843 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2846 hi
->maxlogins
= maxlogins
;
2848 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2849 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
2853 static OPTION_FUNC(opt_advanced
)
2856 if (enabled_string(argv
[1]))
2857 HANDLE_SET_FLAG(hi
, ADVANCED
);
2858 else if (disabled_string(argv
[1]))
2859 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
2861 reply("MSG_INVALID_BINARY", argv
[1]);
2866 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
2870 static OPTION_FUNC(opt_language
)
2872 struct language
*lang
;
2874 lang
= language_find(argv
[1]);
2875 if (irccasecmp(lang
->name
, argv
[1]))
2876 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2877 hi
->language
= lang
;
2879 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
2884 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2885 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2887 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2888 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2889 && (user
->handle_info
->opserv_level
< 1000))) {
2890 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2893 if ((user
->handle_info
->opserv_level
< new_level
)
2894 || ((user
->handle_info
->opserv_level
== new_level
)
2895 && (user
->handle_info
->opserv_level
< 1000))) {
2896 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2899 if (user
->handle_info
== target
) {
2900 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2903 if (target
->opserv_level
== new_level
)
2905 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2906 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2907 target
->opserv_level
= new_level
;
2911 static OPTION_FUNC(opt_level
)
2916 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2920 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2921 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
2925 static OPTION_FUNC(opt_epithet
)
2927 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2929 struct userNode
*target
, *next_un
;
2932 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2936 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2940 if ((epithet
[0] == '*') && !epithet
[1])
2943 hi
->epithet
= strdup(epithet
);
2945 for (target
= hi
->users
; target
; target
= next_un
) {
2946 irc_swhois(nickserv
, target
, hi
->epithet
);
2948 next_un
= target
->next_authed
;
2953 reply("NSMSG_SET_EPITHET", hi
->epithet
);
2955 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2959 static OPTION_FUNC(opt_title
)
2965 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2967 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2972 if(!strcmp(title
, "*")) {
2974 hi
->fakehost
= NULL
;
2977 if (strchr(title
, '.')) {
2978 reply("NSMSG_TITLE_INVALID");
2981 /* Alphanumeric titles only. */
2982 for(sptr
= title
; *sptr
; sptr
++) {
2983 if(!isalnum(*sptr
) && *sptr
!= '-') {
2984 reply("NSMSG_TITLE_INVALID");
2988 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2989 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2990 reply("NSMSG_TITLE_TRUNCATED");
2994 hi
->fakehost
= malloc(strlen(title
)+2);
2995 hi
->fakehost
[0] = '.';
2996 strcpy(hi
->fakehost
+1, title
);
2999 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3000 title
= hi
->fakehost
+ 1;
3002 /* If theres no title set then the default title will therefore
3003 be the first part of hidden_host in x3.conf.example, so for
3004 consistency with opt_fakehost we will print this here */
3005 char *hs
, *hidden_suffix
, *rest
;
3007 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3008 hidden_suffix
= strdup(hs
);
3010 /* Yes we do this twice */
3011 rest
= strrchr(hidden_suffix
, '.');
3013 rest
= strrchr(hidden_suffix
, '.');
3016 title
= hidden_suffix
;
3020 none
= user_find_message(user
, "MSG_NONE");
3021 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3026 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3030 // check for a dot in the vhost
3031 if(strchr(vhost
, '.') == NULL
) {
3032 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3036 // check for a @ in the vhost
3037 if(strchr(vhost
, '@') != NULL
) {
3038 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3042 // check for denied words, inspired by monk at paki.sex
3043 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3044 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3045 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3050 // check for ircu's HOSTLEN length.
3051 if(strlen(vhost
) >= HOSTLEN
) {
3052 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3056 /* This can be handled by the regex now if desired.
3057 if (vhost[strspn(vhost, "0123456789.")]) {
3058 hostname = vhost + strlen(vhost);
3059 for (depth = 1; depth && (hostname > vhost); depth--) {
3061 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3064 if (*hostname == '.') hostname++; * advance past last dot we saw *
3065 if(strlen(hostname) > 4) {
3066 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3071 /* test either regex or as valid handle */
3072 if (nickserv_conf
.valid_fakehost_regex_set
) {
3073 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3076 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3077 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3079 if(err
== REG_NOMATCH
) {
3080 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3089 static OPTION_FUNC(opt_fakehost
)
3093 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3095 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3100 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3101 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3104 if (!strcmp(fake
, "*")) {
3107 hi
->fakehost
= NULL
;
3110 else if (!check_vhost(argv
[1], user
, cmd
)) {
3111 /* check_vhost takes care of error reply */
3117 hi
->fakehost
= strdup(fake
);
3120 fake
= hi
->fakehost
;
3122 fake
= generate_fakehost(hi
);
3124 /* Tell them we set the host */
3126 fake
= user_find_message(user
, "MSG_NONE");
3127 reply("NSMSG_SET_FAKEHOST", fake
);
3131 static OPTION_FUNC(opt_note
)
3134 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3139 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3144 if ((text
[0] == '*') && !text
[1])
3147 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3152 reply("NSMSG_SET_NOTE", hi
->note
->note
);
3156 static NICKSERV_FUNC(cmd_reclaim
)
3158 struct handle_info
*hi
;
3159 struct nick_info
*ni
;
3160 struct userNode
*victim
;
3162 NICKSERV_MIN_PARMS(2);
3163 hi
= user
->handle_info
;
3164 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3166 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3169 if (ni
->owner
!= user
->handle_info
) {
3170 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3173 victim
= GetUserH(ni
->nick
);
3175 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3178 if (victim
== user
) {
3179 reply("NSMSG_NICK_USER_YOU");
3182 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3183 switch (nickserv_conf
.reclaim_action
) {
3184 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3185 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3186 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3187 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3192 static NICKSERV_FUNC(cmd_unregnick
)
3195 struct handle_info
*hi
;
3196 struct nick_info
*ni
;
3198 hi
= user
->handle_info
;
3199 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3200 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3202 reply("NSMSG_UNKNOWN_NICK", nick
);
3205 if (hi
!= ni
->owner
) {
3206 reply("NSMSG_NOT_YOUR_NICK", nick
);
3209 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3214 static NICKSERV_FUNC(cmd_ounregnick
)
3216 struct nick_info
*ni
;
3218 NICKSERV_MIN_PARMS(2);
3219 if (!(ni
= get_nick_info(argv
[1]))) {
3220 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3223 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3224 reply("MSG_USER_OUTRANKED", ni
->nick
);
3227 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3232 static NICKSERV_FUNC(cmd_unregister
)
3234 struct handle_info
*hi
;
3237 NICKSERV_MIN_PARMS(2);
3238 hi
= user
->handle_info
;
3241 if (checkpass(passwd
, hi
->passwd
)) {
3242 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3245 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3246 reply("NSMSG_PASSWORD_INVALID");
3251 static NICKSERV_FUNC(cmd_ounregister
)
3253 struct handle_info
*hi
;
3255 NICKSERV_MIN_PARMS(2);
3256 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
3258 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3262 static NICKSERV_FUNC(cmd_status
)
3264 if (nickserv_conf
.disable_nicks
) {
3265 reply("NSMSG_GLOBAL_STATS_NONICK",
3266 dict_size(nickserv_handle_dict
));
3268 if (user
->handle_info
) {
3270 struct nick_info
*ni
;
3271 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3272 reply("NSMSG_HANDLE_STATS", cnt
);
3274 reply("NSMSG_HANDLE_NONE");
3276 reply("NSMSG_GLOBAL_STATS",
3277 dict_size(nickserv_handle_dict
),
3278 dict_size(nickserv_nick_dict
));
3283 static NICKSERV_FUNC(cmd_ghost
)
3285 struct userNode
*target
;
3286 char reason
[MAXLEN
];
3288 NICKSERV_MIN_PARMS(2);
3289 if (!(target
= GetUserH(argv
[1]))) {
3290 reply("MSG_NICK_UNKNOWN", argv
[1]);
3293 if (target
== user
) {
3294 reply("NSMSG_CANNOT_GHOST_SELF");
3297 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3298 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3301 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3302 DelUser(target
, nickserv
, 1, reason
);
3303 reply("NSMSG_GHOST_KILLED", argv
[1]);
3307 static NICKSERV_FUNC(cmd_vacation
)
3309 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3310 reply("NSMSG_ON_VACATION");
3315 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3317 struct handle_info
*hi
;
3320 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3322 #ifdef WITH_PROTOCOL_BAHAMUT
3325 saxdb_start_record(ctx
, iter_key(it
), 0);
3326 if (hi
->announcements
!= '?') {
3327 flags
[0] = hi
->announcements
;
3329 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3332 struct handle_cookie
*cookie
= hi
->cookie
;
3335 switch (cookie
->type
) {
3336 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3337 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3338 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3339 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3340 default: type
= NULL
; break;
3343 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3344 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3345 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3347 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3348 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3349 saxdb_end_record(ctx
);
3353 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3355 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3357 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3358 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3359 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3360 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3361 saxdb_end_record(ctx
);
3365 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3369 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3370 if (hi
->flags
& (1 << ii
))
3371 flags
[flen
++] = handle_flags
[ii
];
3373 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3375 #ifdef WITH_PROTOCOL_BAHAMUT
3376 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3379 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3380 if (hi
->last_quit_host
[0])
3381 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3382 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3383 if (hi
->masks
->used
)
3384 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3385 if (hi
->ignores
->used
)
3386 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3388 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3390 struct string_list
*slist
;
3391 struct nick_info
*ni
;
3393 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3394 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3395 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3399 if (hi
->opserv_level
)
3400 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3401 if (hi
->language
!= lang_C
)
3402 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3403 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3404 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3405 if (hi
->screen_width
)
3406 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3407 if (hi
->table_width
)
3408 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3409 flags
[0] = hi
->userlist_style
;
3411 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3412 saxdb_end_record(ctx
);
3418 static handle_merge_func_t
*handle_merge_func_list
;
3419 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3422 reg_handle_merge_func(handle_merge_func_t func
)
3424 if (handle_merge_func_used
== handle_merge_func_size
) {
3425 if (handle_merge_func_size
) {
3426 handle_merge_func_size
<<= 1;
3427 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3429 handle_merge_func_size
= 8;
3430 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3433 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3436 static NICKSERV_FUNC(cmd_merge
)
3438 struct handle_info
*hi_from
, *hi_to
;
3439 struct userNode
*last_user
;
3440 struct userData
*cList
, *cListNext
;
3441 unsigned int ii
, jj
, n
;
3442 char buffer
[MAXLEN
];
3444 NICKSERV_MIN_PARMS(3);
3446 if (!(hi_from
= get_victim_oper(cmd
, user
, argv
[1])))
3448 if (!(hi_to
= get_victim_oper(cmd
, user
, argv
[2])))
3450 if (hi_to
== hi_from
) {
3451 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3455 for (n
=0; n
<handle_merge_func_used
; n
++)
3456 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3458 /* Append "from" handle's nicks to "to" handle's nick list. */
3460 struct nick_info
*last_ni
;
3461 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3462 last_ni
->next
= hi_from
->nicks
;
3464 while (hi_from
->nicks
) {
3465 hi_from
->nicks
->owner
= hi_to
;
3466 hi_from
->nicks
= hi_from
->nicks
->next
;
3469 /* Merge the hostmasks. */
3470 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3471 char *mask
= hi_from
->masks
->list
[ii
];
3472 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3473 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3475 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3476 string_list_append(hi_to
->masks
, strdup(mask
));
3479 /* Merge the ignores. */
3480 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3481 char *ignore
= hi_from
->ignores
->list
[ii
];
3482 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3483 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3485 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3486 string_list_append(hi_to
->ignores
, strdup(ignore
));
3489 /* Merge the lists of authed users. */
3491 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3492 last_user
->next_authed
= hi_from
->users
;
3494 hi_to
->users
= hi_from
->users
;
3496 /* Repoint the old "from" handle's users. */
3497 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3498 last_user
->handle_info
= hi_to
;
3500 hi_from
->users
= NULL
;
3502 /* Merge channel userlists. */
3503 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3504 struct userData
*cList2
;
3505 cListNext
= cList
->u_next
;
3506 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3507 if (cList
->channel
== cList2
->channel
)
3509 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3510 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
);
3511 /* keep cList2 in hi_to; remove cList from hi_from */
3512 del_channel_user(cList
, 1);
3515 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
);
3516 /* remove the lower-ranking cList2 from hi_to */
3517 del_channel_user(cList2
, 1);
3519 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3521 /* cList needs to be moved from hi_from to hi_to */
3522 cList
->handle
= hi_to
;
3523 /* Remove from linked list for hi_from */
3524 assert(!cList
->u_prev
);
3525 hi_from
->channels
= cList
->u_next
;
3527 cList
->u_next
->u_prev
= cList
->u_prev
;
3528 /* Add to linked list for hi_to */
3529 cList
->u_prev
= NULL
;
3530 cList
->u_next
= hi_to
->channels
;
3531 if (hi_to
->channels
)
3532 hi_to
->channels
->u_prev
= cList
;
3533 hi_to
->channels
= cList
;
3537 /* Do they get an OpServ level promotion? */
3538 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3539 hi_to
->opserv_level
= hi_from
->opserv_level
;
3541 /* What about last seen time? */
3542 if (hi_from
->lastseen
> hi_to
->lastseen
)
3543 hi_to
->lastseen
= hi_from
->lastseen
;
3545 /* Does a fakehost carry over? (This intentionally doesn't set it
3546 * for users previously attached to hi_to. They'll just have to
3549 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3550 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3552 /* Notify of success. */
3553 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3554 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3555 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3557 /* Unregister the "from" handle. */
3558 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3563 struct nickserv_discrim
{
3564 unsigned int limit
, min_level
, max_level
;
3565 unsigned long flags_on
, flags_off
;
3566 time_t min_registered
, max_registered
;
3568 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3569 const char *nickmask
;
3570 const char *hostmask
;
3571 const char *handlemask
;
3572 const char *emailmask
;
3575 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3577 struct discrim_apply_info
{
3578 struct nickserv_discrim
*discrim
;
3579 discrim_search_func func
;
3580 struct userNode
*source
;
3581 unsigned int matched
;
3584 static struct nickserv_discrim
*
3585 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
3588 struct nickserv_discrim
*discrim
;
3590 discrim
= malloc(sizeof(*discrim
));
3591 memset(discrim
, 0, sizeof(*discrim
));
3592 discrim
->min_level
= 0;
3593 discrim
->max_level
= ~0;
3594 discrim
->limit
= 50;
3595 discrim
->min_registered
= 0;
3596 discrim
->max_registered
= INT_MAX
;
3597 discrim
->lastseen
= now
;
3599 for (i
=0; i
<argc
; i
++) {
3600 if (i
== argc
- 1) {
3601 reply("MSG_MISSING_PARAMS", argv
[i
]);
3604 if (!irccasecmp(argv
[i
], "limit")) {
3605 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3606 } else if (!irccasecmp(argv
[i
], "flags")) {
3607 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3608 } else if (!irccasecmp(argv
[i
], "registered")) {
3609 const char *cmp
= argv
[++i
];
3610 if (cmp
[0] == '<') {
3611 if (cmp
[1] == '=') {
3612 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3614 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3616 } else if (cmp
[0] == '=') {
3617 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3618 } else if (cmp
[0] == '>') {
3619 if (cmp
[1] == '=') {
3620 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3622 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3625 reply("MSG_INVALID_CRITERIA", cmp
);
3627 } else if (!irccasecmp(argv
[i
], "seen")) {
3628 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3629 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3630 discrim
->nickmask
= argv
[++i
];
3631 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3633 if (!irccasecmp(argv
[i
], "exact")) {
3634 if (i
== argc
- 1) {
3635 reply("MSG_MISSING_PARAMS", argv
[i
]);
3638 discrim
->hostmask_type
= EXACT
;
3639 } else if (!irccasecmp(argv
[i
], "subset")) {
3640 if (i
== argc
- 1) {
3641 reply("MSG_MISSING_PARAMS", argv
[i
]);
3644 discrim
->hostmask_type
= SUBSET
;
3645 } else if (!irccasecmp(argv
[i
], "superset")) {
3646 if (i
== argc
- 1) {
3647 reply("MSG_MISSING_PARAMS", argv
[i
]);
3650 discrim
->hostmask_type
= SUPERSET
;
3651 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3652 if (i
== argc
- 1) {
3653 reply("MSG_MISSING_PARAMS", argv
[i
]);
3656 discrim
->hostmask_type
= LASTQUIT
;
3659 discrim
->hostmask_type
= SUPERSET
;
3661 discrim
->hostmask
= argv
[++i
];
3662 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3663 if (!irccasecmp(argv
[++i
], "*")) {
3664 discrim
->handlemask
= 0;
3666 discrim
->handlemask
= argv
[i
];
3668 } else if (!irccasecmp(argv
[i
], "email")) {
3669 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3670 reply("MSG_NO_SEARCH_ACCESS", "email");
3672 } else if (!irccasecmp(argv
[++i
], "*")) {
3673 discrim
->emailmask
= 0;
3675 discrim
->emailmask
= argv
[i
];
3677 } else if (!irccasecmp(argv
[i
], "access")) {
3678 const char *cmp
= argv
[++i
];
3679 if (cmp
[0] == '<') {
3680 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3681 if (cmp
[1] == '=') {
3682 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3684 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3686 } else if (cmp
[0] == '=') {
3687 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3688 } else if (cmp
[0] == '>') {
3689 if (cmp
[1] == '=') {
3690 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3692 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3695 reply("MSG_INVALID_CRITERIA", cmp
);
3698 reply("MSG_INVALID_CRITERIA", argv
[i
]);
3709 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3711 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3712 || (discrim
->flags_off
& hi
->flags
)
3713 || (discrim
->min_registered
> hi
->registered
)
3714 || (discrim
->max_registered
< hi
->registered
)
3715 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3716 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3717 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3718 || (discrim
->min_level
> hi
->opserv_level
)
3719 || (discrim
->max_level
< hi
->opserv_level
)) {
3722 if (discrim
->hostmask
) {
3724 for (i
=0; i
<hi
->masks
->used
; i
++) {
3725 const char *mask
= hi
->masks
->list
[i
];
3726 if ((discrim
->hostmask_type
== SUBSET
)
3727 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3728 else if ((discrim
->hostmask_type
== EXACT
)
3729 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3730 else if ((discrim
->hostmask_type
== SUPERSET
)
3731 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3732 else if ((discrim
->hostmask_type
== LASTQUIT
)
3733 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3735 if (i
==hi
->masks
->used
) return 0;
3737 if (discrim
->nickmask
) {
3738 struct nick_info
*nick
= hi
->nicks
;
3740 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3743 if (!nick
) return 0;
3749 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3751 dict_iterator_t it
, next
;
3752 unsigned int matched
;
3754 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3755 it
&& (matched
< discrim
->limit
);
3757 next
= iter_next(it
);
3758 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3759 dsf(source
, iter_data(it
));
3767 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3769 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3773 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3778 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3780 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3781 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3785 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3787 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3788 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3789 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3790 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3791 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3795 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3797 struct handle_info_list hil
;
3798 struct helpfile_table tbl
;
3803 memset(&hil
, 0, sizeof(hil
));
3804 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3805 struct handle_info
*hi
= iter_data(it
);
3806 if (hi
->opserv_level
)
3807 handle_info_list_append(&hil
, hi
);
3809 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3810 tbl
.length
= hil
.used
+ 1;
3812 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
3813 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3814 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3817 for (ii
= 0; ii
< hil
.used
; ) {
3818 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3819 ary
[0] = hil
.list
[ii
]->handle
;
3820 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3821 tbl
.contents
[++ii
] = ary
;
3823 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3824 /*reply("MSG_MATCH_COUNT", hil.used); */
3825 for (ii
= 0; ii
< hil
.used
; ii
++)
3826 free(tbl
.contents
[ii
]);
3831 static NICKSERV_FUNC(cmd_search
)
3833 struct nickserv_discrim
*discrim
;
3834 discrim_search_func action
;
3835 struct svccmd
*subcmd
;
3836 unsigned int matches
;
3839 NICKSERV_MIN_PARMS(3);
3840 sprintf(buf
, "search %s", argv
[1]);
3841 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3842 if (!irccasecmp(argv
[1], "print"))
3843 action
= search_print_func
;
3844 else if (!irccasecmp(argv
[1], "count"))
3845 action
= search_count_func
;
3846 else if (!irccasecmp(argv
[1], "unregister"))
3847 action
= search_unregister_func
;
3849 reply("NSMSG_INVALID_ACTION", argv
[1]);
3853 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3856 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
3860 if (action
== search_print_func
)
3861 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3862 else if (action
== search_count_func
)
3863 discrim
->limit
= INT_MAX
;
3865 matches
= nickserv_discrim_search(discrim
, action
, user
);
3868 reply("MSG_MATCH_COUNT", matches
);
3870 reply("MSG_NO_MATCHES");
3876 static MODCMD_FUNC(cmd_checkpass
)
3878 struct handle_info
*hi
;
3880 NICKSERV_MIN_PARMS(3);
3881 if (!(hi
= get_handle_info(argv
[1]))) {
3882 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3885 if (checkpass(argv
[2], hi
->passwd
))
3886 reply("CHECKPASS_YES");
3888 reply("CHECKPASS_NO");
3894 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3897 struct string_list
*masks
, *slist
, *ignores
;
3898 struct handle_info
*hi
;
3899 struct userNode
*authed_users
;
3900 struct userData
*channels
;
3901 unsigned long int id
;
3904 char *setter
, *note
;
3907 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3908 id
= str
? strtoul(str
, NULL
, 0) : 0;
3909 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3911 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3914 if ((hi
= get_handle_info(handle
))) {
3915 authed_users
= hi
->users
;
3916 channels
= hi
->channels
;
3918 hi
->channels
= NULL
;
3919 dict_remove(nickserv_handle_dict
, hi
->handle
);
3921 authed_users
= NULL
;
3924 hi
= register_handle(handle
, str
, id
);
3926 hi
->users
= authed_users
;
3927 while (authed_users
) {
3928 authed_users
->handle_info
= hi
;
3929 authed_users
= authed_users
->next_authed
;
3932 hi
->channels
= channels
;
3933 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3934 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3935 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
3936 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
3937 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3938 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3939 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3940 hi
->language
= language_find(str
? str
: "C");
3941 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3942 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3943 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3945 hi
->infoline
= strdup(str
);
3946 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3947 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3948 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3949 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3950 /* We want to read the nicks even if disable_nicks is set. This is so
3951 * that we don't lose the nick data entirely. */
3952 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3954 for (ii
=0; ii
<slist
->used
; ii
++)
3955 register_nick(slist
->list
[ii
], hi
);
3957 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3959 for (ii
=0; str
[ii
]; ii
++)
3960 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3962 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3963 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3964 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3965 hi
->announcements
= str
? str
[0] : '?';
3966 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3967 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3968 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3969 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3970 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3972 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3974 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3975 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3977 nickserv_set_email_addr(hi
, str
);
3978 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3980 hi
->epithet
= strdup(str
);
3981 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3983 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3984 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3985 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3986 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3987 if (setter
&& date
&& note
)
3989 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3994 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3996 hi
->fakehost
= strdup(str
);
3998 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4000 const char *data
, *type
, *expires
, *cookie_str
;
4001 struct handle_cookie
*cookie
;
4003 cookie
= calloc(1, sizeof(*cookie
));
4004 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4005 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4006 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4007 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4008 if (!type
|| !expires
|| !cookie_str
) {
4009 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4012 if (!irccasecmp(type
, KEY_ACTIVATION
))
4013 cookie
->type
= ACTIVATION
;
4014 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4015 cookie
->type
= PASSWORD_CHANGE
;
4016 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4017 cookie
->type
= EMAIL_CHANGE
;
4018 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4019 cookie
->type
= ALLOWAUTH
;
4021 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4024 cookie
->expires
= strtoul(expires
, NULL
, 0);
4025 if (cookie
->expires
< now
)
4028 cookie
->data
= strdup(data
);
4029 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4033 nickserv_bake_cookie(cookie
);
4035 nickserv_free_cookie(cookie
);
4040 nickserv_saxdb_read(dict_t db
) {
4042 struct record_data
*rd
;
4044 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4046 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
4051 static NICKSERV_FUNC(cmd_mergedb
)
4053 struct timeval start
, stop
;
4056 NICKSERV_MIN_PARMS(2);
4057 gettimeofday(&start
, NULL
);
4058 if (!(db
= parse_database(argv
[1]))) {
4059 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4062 nickserv_saxdb_read(db
);
4064 gettimeofday(&stop
, NULL
);
4065 stop
.tv_sec
-= start
.tv_sec
;
4066 stop
.tv_usec
-= start
.tv_usec
;
4067 if (stop
.tv_usec
< 0) {
4069 stop
.tv_usec
+= 1000000;
4071 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4076 expire_handles(UNUSED_ARG(void *data
))
4078 dict_iterator_t it
, next
;
4080 struct handle_info
*hi
;
4082 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4083 next
= iter_next(it
);
4085 if ((hi
->opserv_level
> 0)
4087 || HANDLE_FLAGGED(hi
, FROZEN
)
4088 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4091 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4092 if ((now
- hi
->lastseen
) > expiry
) {
4093 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4094 nickserv_unregister_handle(hi
, NULL
, NULL
);
4098 if (nickserv_conf
.handle_expire_frequency
)
4099 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4103 nickserv_load_dict(const char *fname
)
4107 if (!(file
= fopen(fname
, "r"))) {
4108 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4111 while (!feof(file
)) {
4112 fgets(line
, sizeof(line
), file
);
4115 if (line
[strlen(line
)-1] == '\n')
4116 line
[strlen(line
)-1] = 0;
4117 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4120 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4123 static enum reclaim_action
4124 reclaim_action_from_string(const char *str
) {
4126 return RECLAIM_NONE
;
4127 else if (!irccasecmp(str
, "warn"))
4128 return RECLAIM_WARN
;
4129 else if (!irccasecmp(str
, "svsnick"))
4130 return RECLAIM_SVSNICK
;
4131 else if (!irccasecmp(str
, "kill"))
4132 return RECLAIM_KILL
;
4134 return RECLAIM_NONE
;
4138 nickserv_conf_read(void)
4140 dict_t conf_node
, child
;
4143 struct string_list
*strlist
;
4145 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4146 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4149 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4151 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4152 if (nickserv_conf
.valid_handle_regex_set
)
4153 regfree(&nickserv_conf
.valid_handle_regex
);
4155 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4156 nickserv_conf
.valid_handle_regex_set
= !err
;
4157 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4159 nickserv_conf
.valid_handle_regex_set
= 0;
4161 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4162 if (nickserv_conf
.valid_nick_regex_set
)
4163 regfree(&nickserv_conf
.valid_nick_regex
);
4165 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4166 nickserv_conf
.valid_nick_regex_set
= !err
;
4167 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4169 nickserv_conf
.valid_nick_regex_set
= 0;
4171 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4172 if (nickserv_conf
.valid_fakehost_regex_set
)
4173 regfree(&nickserv_conf
.valid_fakehost_regex
);
4175 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4176 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4177 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4179 nickserv_conf
.valid_fakehost_regex_set
= 0;
4181 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4183 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4184 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4185 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4186 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4187 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4188 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4189 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4190 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4191 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4192 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4193 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4194 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4195 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4196 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4197 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4198 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4199 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4200 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4201 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4202 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4203 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4204 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4205 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4206 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4207 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4209 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4210 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4211 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4213 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4214 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4215 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4217 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4218 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4219 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4220 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4221 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4222 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4223 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4224 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4225 if (!nickserv_conf
.disable_nicks
) {
4226 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4227 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4228 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4229 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4230 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4231 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4232 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4233 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4235 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4236 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4237 const char *key
= iter_key(it
), *value
;
4241 if (!strncasecmp(key
, "uc_", 3))
4242 flag
= toupper(key
[3]);
4243 else if (!strncasecmp(key
, "lc_", 3))
4244 flag
= tolower(key
[3]);
4248 if ((pos
= handle_inverse_flags
[flag
])) {
4249 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4250 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4253 if (nickserv_conf
.weak_password_dict
)
4254 dict_delete(nickserv_conf
.weak_password_dict
);
4255 nickserv_conf
.weak_password_dict
= dict_new();
4256 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4257 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4258 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4259 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4261 nickserv_load_dict(str
);
4262 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4263 if (nickserv
&& str
)
4264 NickChange(nickserv
, str
, 0);
4265 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4266 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4267 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4268 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4269 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4270 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4271 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4272 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4273 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4274 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4275 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4276 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4277 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4278 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4279 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4280 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4281 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4282 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4283 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4284 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4286 free_string_list(nickserv_conf
.denied_fakehost_words
);
4287 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4289 strlist
= string_list_copy(strlist
);
4291 strlist
= alloc_string_list(4);
4292 string_list_append(strlist
, strdup("sex"));
4293 string_list_append(strlist
, strdup("fuck"));
4295 nickserv_conf
.denied_fakehost_words
= strlist
;
4297 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4298 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4300 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4301 nickserv_conf
.auto_oper
= str
? str
: "";
4303 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4304 nickserv_conf
.auto_admin
= str
? str
: "";
4306 str
= conf_get_data("server/network", RECDB_QSTRING
);
4307 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4308 if (!nickserv_conf
.auth_policer_params
) {
4309 nickserv_conf
.auth_policer_params
= policer_params_new();
4310 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4311 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4313 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4314 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4315 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4319 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4321 char newnick
[NICKLEN
+1];
4330 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4332 case RECLAIM_SVSNICK
:
4334 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4335 } while (GetUserH(newnick
));
4336 irc_svsnick(nickserv
, user
, newnick
);
4339 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4340 irc_kill(nickserv
, user
, msg
);
4346 nickserv_reclaim_p(void *data
) {
4347 struct userNode
*user
= data
;
4348 struct nick_info
*ni
= get_nick_info(user
->nick
);
4350 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4354 check_user_nick(struct userNode
*user
) {
4355 struct nick_info
*ni
;
4356 user
->modes
&= ~FLAGS_REGNICK
;
4357 if (!(ni
= get_nick_info(user
->nick
)))
4359 if (user
->handle_info
== ni
->owner
) {
4360 user
->modes
|= FLAGS_REGNICK
;
4364 if (nickserv_conf
.warn_nick_owned
)
4365 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4366 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4368 if (nickserv_conf
.auto_reclaim_delay
)
4369 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4371 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4376 handle_new_user(struct userNode
*user
)
4378 return check_user_nick(user
);
4382 handle_account(struct userNode
*user
, const char *stamp
)
4384 struct handle_info
*hi
;
4387 #ifdef WITH_PROTOCOL_P10
4388 time_t timestamp
= 0;
4390 colon
= strchr(stamp
, ':');
4391 if(colon
&& colon
[1])
4394 timestamp
= atoi(colon
+1);
4396 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4397 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4399 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
);
4403 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4404 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4408 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4411 set_user_handle_info(user
, hi
, 0);
4413 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4418 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4420 struct handle_info
*hi
;
4422 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4423 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4424 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4426 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4427 check_user_nick(user
);
4431 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4433 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4434 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4435 set_user_handle_info(user
, NULL
, 0);
4438 static struct modcmd
*
4439 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4441 if (min_level
> 0) {
4443 sprintf(buf
, "%u", min_level
);
4444 if (must_be_qualified
) {
4445 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4447 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4449 } else if (min_level
== 0) {
4450 if (must_be_qualified
) {
4451 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4453 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4456 if (must_be_qualified
) {
4457 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4459 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4465 nickserv_db_cleanup(void)
4467 unreg_del_user_func(nickserv_remove_user
);
4468 userList_clean(&curr_helpers
);
4469 policer_params_delete(nickserv_conf
.auth_policer_params
);
4470 dict_delete(nickserv_handle_dict
);
4471 dict_delete(nickserv_nick_dict
);
4472 dict_delete(nickserv_opt_dict
);
4473 dict_delete(nickserv_allow_auth_dict
);
4474 dict_delete(nickserv_email_dict
);
4475 dict_delete(nickserv_id_dict
);
4476 dict_delete(nickserv_conf
.weak_password_dict
);
4477 free(auth_func_list
);
4478 free(unreg_func_list
);
4480 free(allowauth_func_list
);
4481 free(handle_merge_func_list
);
4482 free(failpw_func_list
);
4483 if (nickserv_conf
.valid_handle_regex_set
)
4484 regfree(&nickserv_conf
.valid_handle_regex
);
4485 if (nickserv_conf
.valid_nick_regex_set
)
4486 regfree(&nickserv_conf
.valid_nick_regex
);
4490 init_nickserv(const char *nick
)
4492 struct chanNode
*chan
;
4494 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4495 reg_new_user_func(handle_new_user
);
4496 reg_nick_change_func(handle_nick_change
);
4497 reg_del_user_func(nickserv_remove_user
);
4498 reg_account_func(handle_account
);
4500 /* set up handle_inverse_flags */
4501 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4502 for (i
=0; handle_flags
[i
]; i
++) {
4503 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4504 flag_access_levels
[i
] = 0;
4507 conf_register_reload(nickserv_conf_read
);
4508 nickserv_opt_dict
= dict_new();
4509 nickserv_email_dict
= dict_new();
4511 dict_set_free_keys(nickserv_email_dict
, free
);
4512 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4514 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4515 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4516 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4517 * a big pain to disable since its nolonger in the config file. ) -Rubin
4519 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4520 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4521 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4522 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4523 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4524 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4525 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4526 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4527 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4528 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4529 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4530 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4531 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4532 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4533 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4534 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4535 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4536 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4537 if (!nickserv_conf
.disable_nicks
) {
4538 /* nick management commands */
4539 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4540 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4541 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4542 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4543 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4544 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4546 if (nickserv_conf
.email_enabled
) {
4547 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4548 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4549 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4550 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4551 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4552 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4554 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4555 /* ignore commands */
4556 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
4557 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
4558 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
4559 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
4560 /* miscellaneous commands */
4561 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4562 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4563 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4564 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4565 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4567 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4568 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4569 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4570 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4571 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4572 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4573 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4574 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4575 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4576 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4577 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4578 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4579 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4580 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4581 if (nickserv_conf
.titlehost_suffix
) {
4582 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4583 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4585 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4586 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4587 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
4588 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4590 nickserv_handle_dict
= dict_new();
4591 dict_set_free_keys(nickserv_handle_dict
, free
);
4592 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4594 nickserv_id_dict
= dict_new();
4595 dict_set_free_keys(nickserv_id_dict
, free
);
4597 nickserv_nick_dict
= dict_new();
4598 dict_set_free_data(nickserv_nick_dict
, free
);
4600 nickserv_allow_auth_dict
= dict_new();
4602 userList_init(&curr_helpers
);
4605 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4606 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4607 nickserv_service
= service_register(nickserv
);
4609 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4610 reg_exit_func(nickserv_db_cleanup
);
4611 if(nickserv_conf
.handle_expire_frequency
)
4612 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4614 if(autojoin_channels
&& nickserv
) {
4615 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
4616 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
4617 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
4621 message_register_table(msgtab
);