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 hi
= calloc(1, sizeof(*hi
));
463 hi
->userlist_style
= HI_DEFAULT_STYLE
;
464 hi
->announcements
= '?';
465 hi
->handle
= strdup(handle
);
466 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
468 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
474 register_nick(const char *nick
, struct handle_info
*owner
)
476 struct nick_info
*ni
;
477 ni
= malloc(sizeof(struct nick_info
));
478 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
480 ni
->next
= owner
->nicks
;
482 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
486 delete_nick(struct nick_info
*ni
)
488 struct nick_info
*last
, *next
;
489 struct userNode
*user
;
490 /* Check to see if we should mark a user as unregistered. */
491 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
492 user
->modes
&= ~FLAGS_REGNICK
;
495 /* Remove ni from the nick_info linked list. */
496 if (ni
== ni
->owner
->nicks
) {
497 ni
->owner
->nicks
= ni
->next
;
499 last
= ni
->owner
->nicks
;
505 last
->next
= next
->next
;
507 dict_remove(nickserv_nick_dict
, ni
->nick
);
510 static unreg_func_t
*unreg_func_list
;
511 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
514 reg_unreg_func(unreg_func_t func
)
516 if (unreg_func_used
== unreg_func_size
) {
517 if (unreg_func_size
) {
518 unreg_func_size
<<= 1;
519 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
522 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
525 unreg_func_list
[unreg_func_used
++] = func
;
529 nickserv_free_cookie(void *data
)
531 struct handle_cookie
*cookie
= data
;
532 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
533 if (cookie
->data
) free(cookie
->data
);
538 free_handle_info(void *vhi
)
540 struct handle_info
*hi
= vhi
;
542 free_string_list(hi
->masks
);
543 free_string_list(hi
->ignores
);
547 delete_nick(hi
->nicks
);
553 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
554 nickserv_free_cookie(hi
->cookie
);
556 if (hi
->email_addr
) {
557 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
558 handle_info_list_remove(hil
, hi
);
560 dict_remove(nickserv_email_dict
, hi
->email_addr
);
565 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
568 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
571 struct userNode
*uNode
;
573 for (n
=0; n
<unreg_func_used
; n
++)
574 unreg_func_list
[n
](notify
, hi
);
576 if (nickserv_conf
.sync_log
) {
577 uNode
= GetUserH(hi
->users
->nick
);
581 set_user_handle_info(hi
->users
, NULL
, 0);
584 if (nickserv_conf
.disable_nicks
)
585 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
587 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
590 if (nickserv_conf
.sync_log
)
591 SyncLog("UNREGISTER %s", hi
->handle
);
593 dict_remove(nickserv_handle_dict
, hi
->handle
);
597 get_handle_info(const char *handle
)
599 return dict_find(nickserv_handle_dict
, handle
, 0);
603 get_nick_info(const char *nick
)
605 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
609 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
614 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
615 mn
= channel
->members
.list
[nn
];
616 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
623 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
624 if (!user
->handle_info
) {
626 send_message(user
, bot
, "MSG_AUTHENTICATE");
630 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
632 send_message(user
, bot
, "NSMSG_NO_ACCESS");
636 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
638 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
642 if (user
->handle_info
->opserv_level
< min_level
) {
644 send_message(user
, bot
, "NSMSG_NO_ACCESS");
652 is_valid_handle(const char *handle
)
654 struct userNode
*user
;
655 /* cant register a juped nick/service nick as handle, to prevent confusion */
656 user
= GetUserH(handle
);
657 if (user
&& IsLocal(user
))
659 /* check against maximum length */
660 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
662 /* for consistency, only allow account names that could be nicks */
663 if (!is_valid_nick(handle
))
665 /* disallow account names that look like bad words */
666 if (opserv_bad_channel(handle
))
668 /* test either regex or containing all valid chars */
669 if (nickserv_conf
.valid_handle_regex_set
) {
670 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
673 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
674 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
678 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
683 is_registerable_nick(const char *nick
)
685 /* make sure it could be used as an account name */
686 if (!is_valid_handle(nick
))
689 if (strlen(nick
) > NICKLEN
)
691 /* test either regex or as valid handle */
692 if (nickserv_conf
.valid_nick_regex_set
) {
693 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
696 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
697 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
703 /* this has been replaced with one in tools.c
706 is_valid_email_addr(const char *email)
708 return strchr(email, '@') != NULL;
714 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
716 if (hi
->email_addr
) {
717 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
718 return hi
->email_addr
;
728 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
730 struct handle_info
*hi
;
731 struct userNode
*target
;
735 if (!(hi
= get_handle_info(++name
))) {
736 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
741 if (!(target
= GetUserH(name
))) {
742 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
745 if (IsLocal(target
)) {
746 if (IsService(target
))
747 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
749 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
752 if (!(hi
= target
->handle_info
)) {
753 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
761 oper_outranks(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
) {
762 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
764 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
765 if ((user
->handle_info
->opserv_level
== 1000)
766 || (user
->handle_info
== hi
)
767 || ((user
->handle_info
->opserv_level
== 0)
768 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
769 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
773 reply("MSG_USER_OUTRANKED", hi
->handle
);
778 get_victim_oper(struct svccmd
*cmd
, struct userNode
*user
, const char *target
)
780 struct handle_info
*hi
;
781 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
783 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
784 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
787 return oper_outranks(cmd
, user
, hi
) ? hi
: NULL
;
791 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
795 /* If no hostmasks on the account, allow it. */
796 if (!hi
->masks
->used
)
798 /* If any hostmask matches, allow it. */
799 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
800 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
802 /* If they are allowauthed to this account, allow it (removing the aa). */
803 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
804 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
807 /* The user is not allowed to use this account. */
812 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
815 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
819 if (len
< nickserv_conf
.password_min_length
) {
821 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
824 if (!irccasecmp(pass
, handle
)) {
826 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
829 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
832 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
835 for (i
=0; i
<len
; i
++) {
836 if (isdigit(pass
[i
]))
838 if (isupper(pass
[i
]))
840 if (islower(pass
[i
]))
843 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
844 || (cnt_upper
< nickserv_conf
.password_min_upper
)
845 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
847 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
853 static auth_func_t
*auth_func_list
;
854 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
857 reg_auth_func(auth_func_t func
)
859 if (auth_func_used
== auth_func_size
) {
860 if (auth_func_size
) {
861 auth_func_size
<<= 1;
862 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
865 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
868 auth_func_list
[auth_func_used
++] = func
;
871 static handle_rename_func_t
*rf_list
;
872 static unsigned int rf_list_size
, rf_list_used
;
875 reg_handle_rename_func(handle_rename_func_t func
)
877 if (rf_list_used
== rf_list_size
) {
880 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
883 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
886 rf_list
[rf_list_used
++] = func
;
890 generate_fakehost(struct handle_info
*handle
)
892 struct userNode
*target
;
893 extern const char *hidden_host_suffix
;
894 static char buffer
[HOSTLEN
+1];
898 if (!handle
->fakehost
) {
899 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
904 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
905 else if (style
== 2) {
906 /* Due to the way fakehost is coded theres no way i can
907 get the exact user, so for now ill just take the first
909 for (target
= handle
->users
; target
; target
= target
->next_authed
)
912 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
915 } else if (handle
->fakehost
[0] == '.') {
916 /* A leading dot indicates the stored value is actually a title. */
917 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
920 return handle
->fakehost
;
924 apply_fakehost(struct handle_info
*handle
)
926 struct userNode
*target
;
931 fake
= generate_fakehost(handle
);
932 for (target
= handle
->users
; target
; target
= target
->next_authed
)
933 assign_fakehost(target
, fake
, 1);
936 void send_func_list(struct userNode
*user
)
939 struct handle_info
*old_info
;
941 old_info
= user
->handle_info
;
943 for (n
=0; n
<auth_func_used
; n
++)
944 auth_func_list
[n
](user
, old_info
);
948 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
951 struct handle_info
*old_info
;
953 /* This can happen if somebody uses COOKIE while authed, or if
954 * they re-auth to their current handle (which is silly, but users
956 if (user
->handle_info
== hi
)
959 if (user
->handle_info
) {
960 struct userNode
*other
;
963 userList_remove(&curr_helpers
, user
);
965 /* remove from next_authed linked list */
966 if (user
->handle_info
->users
== user
) {
967 user
->handle_info
->users
= user
->next_authed
;
969 for (other
= user
->handle_info
->users
;
970 other
->next_authed
!= user
;
971 other
= other
->next_authed
) ;
972 other
->next_authed
= user
->next_authed
;
974 /* if nobody left on old handle, and they're not an oper, remove !god */
975 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
976 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
977 /* record them as being last seen at this time */
978 user
->handle_info
->lastseen
= now
;
979 /* and record their hostmask */
980 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
982 old_info
= user
->handle_info
;
983 user
->handle_info
= hi
;
984 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
985 HANDLE_CLEAR_FLAG(hi
, HELPING
);
987 if (GetUserH(user
->nick
)) {
988 for (n
=0; n
<auth_func_used
; n
++)
989 auth_func_list
[n
](user
, old_info
);
994 struct nick_info
*ni
;
996 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
997 if (nickserv_conf
.warn_clone_auth
) {
998 struct userNode
*other
;
999 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1000 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1003 user
->next_authed
= hi
->users
;
1007 userList_append(&curr_helpers
, user
);
1009 if (hi
->fakehost
|| old_info
)
1013 #ifdef WITH_PROTOCOL_P10
1014 /* Stamp users with their account name. */
1015 char *id
= hi
->handle
;
1017 const char *id
= "???";
1019 if (!nickserv_conf
.disable_nicks
) {
1020 struct nick_info
*ni
;
1021 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1022 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1023 user
->modes
|= FLAGS_REGNICK
;
1028 StampUser(user
, id
, hi
->registered
);
1031 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1032 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1034 /* We cannot clear the user's account ID, unfortunately. */
1035 user
->next_authed
= NULL
;
1039 static struct handle_info
*
1040 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1042 struct handle_info
*hi
;
1043 struct nick_info
*ni
;
1044 char crypted
[MD5_CRYPT_LENGTH
];
1046 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1047 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1051 if(strlen(handle
) > 15)
1053 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1057 if (!is_secure_password(handle
, passwd
, user
))
1060 cryptpass(passwd
, crypted
);
1061 hi
= register_handle(handle
, crypted
, 0);
1062 hi
->masks
= alloc_string_list(1);
1063 hi
->ignores
= alloc_string_list(1);
1065 hi
->language
= lang_C
;
1066 hi
->registered
= now
;
1068 hi
->flags
= HI_DEFAULT_FLAGS
;
1069 if (settee
&& !no_auth
)
1070 set_user_handle_info(settee
, hi
, 1);
1073 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1074 else if (nickserv_conf
.disable_nicks
)
1075 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1076 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1077 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1079 register_nick(user
->nick
, hi
);
1080 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1082 if (settee
&& (user
!= settee
))
1083 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1088 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1090 cookie
->hi
->cookie
= cookie
;
1091 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1094 /* Contributed by the great sneep of afternet ;) */
1095 /* Since this gets used in a URL, we want to avoid stuff that confuses
1096 * email clients such as ] and ?. a-z, 0-9 only.
1098 void genpass(char *str
, int len
)
1103 for(i
= 0; i
< len
; i
++)
1107 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1108 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1116 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1118 struct handle_cookie
*cookie
;
1119 char subject
[128], body
[4096], *misc
;
1120 const char *netname
, *fmt
;
1124 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1128 cookie
= calloc(1, sizeof(*cookie
));
1130 cookie
->type
= type
;
1131 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1133 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1134 /* Adding dedicated password gen function for more control -Rubin */
1135 genpass(cookie
->cookie
, 10);
1137 *inttobase64(cookie->cookie, rand(), 5);
1138 *inttobase64(cookie->cookie+5, rand(), 5);
1141 netname
= nickserv_conf
.network_name
;
1144 switch (cookie
->type
) {
1146 hi
->passwd
[0] = 0; /* invalidate password */
1147 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1148 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1149 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1152 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1154 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1156 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1159 case PASSWORD_CHANGE
:
1160 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1161 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1162 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1164 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1166 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1167 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1170 misc
= hi
->email_addr
;
1171 hi
->email_addr
= cookie
->data
;
1172 #ifdef stupid_verify_old_email
1174 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1175 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1176 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1177 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1178 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1179 sendmail(nickserv
, hi
, subject
, body
, 1);
1180 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1181 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1184 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1185 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1186 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1187 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1188 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1189 sendmail(nickserv
, hi
, subject
, body
, 1);
1191 #ifdef stupid_verify_old_email
1194 hi
->email_addr
= misc
;
1197 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1198 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1199 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1200 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1201 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1204 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1208 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1209 nickserv_bake_cookie(cookie
);
1213 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1215 cookie
->hi
->cookie
= NULL
;
1216 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1217 nickserv_free_cookie(cookie
);
1221 nickserv_free_email_addr(void *data
)
1223 handle_info_list_clean(data
);
1228 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1230 struct handle_info_list
*hil
;
1231 /* Remove from old handle_info_list ... */
1232 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1233 handle_info_list_remove(hil
, hi
);
1234 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1235 hi
->email_addr
= NULL
;
1237 /* Add to the new list.. */
1238 if (new_email_addr
) {
1239 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1240 hil
= calloc(1, sizeof(*hil
));
1241 hil
->tag
= strdup(new_email_addr
);
1242 handle_info_list_init(hil
);
1243 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1245 handle_info_list_append(hil
, hi
);
1246 hi
->email_addr
= hil
->tag
;
1250 static NICKSERV_FUNC(cmd_register
)
1253 struct handle_info
*hi
;
1254 const char *email_addr
, *password
;
1255 char syncpass
[MD5_CRYPT_LENGTH
];
1256 int no_auth
, weblink
;
1258 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1259 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1263 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1264 /* Require the first handle registered to belong to someone +o. */
1265 reply("NSMSG_REQUIRE_OPER");
1269 if (user
->handle_info
) {
1270 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1274 if (IsRegistering(user
)) {
1275 reply("NSMSG_ALREADY_REGISTERING");
1279 if (IsStamped(user
)) {
1280 /* Unauthenticated users might still have been stamped
1281 previously and could therefore have a hidden host;
1282 do not allow them to register a new account. */
1283 reply("NSMSG_STAMPED_REGISTER");
1287 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1289 if (!is_valid_handle(argv
[1])) {
1290 reply("NSMSG_BAD_HANDLE", argv
[1]);
1295 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1296 struct handle_info_list
*hil
;
1299 /* Remember email address. */
1300 email_addr
= argv
[3];
1302 /* Check that the email address looks valid.. */
1303 if (!valid_email(email_addr
)) {
1304 reply("NSMSG_BAD_EMAIL_ADDR");
1308 /* .. and that we are allowed to send to it. */
1309 if ((str
= sendmail_prohibited_address(email_addr
))) {
1310 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1314 /* If we do email verify, make sure we don't spam the address. */
1315 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1317 for (nn
=0; nn
<hil
->used
; nn
++) {
1318 if (hil
->list
[nn
]->cookie
) {
1319 reply("NSMSG_EMAIL_UNACTIVATED");
1323 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1324 reply("NSMSG_EMAIL_OVERUSED");
1337 /* Webregister hack - send URL instead of IRC cookie
1340 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1344 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1346 /* Add any masks they should get. */
1347 if (nickserv_conf
.default_hostmask
) {
1348 string_list_append(hi
->masks
, strdup("*@*"));
1350 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1351 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1352 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1355 /* If they're the first to register, give them level 1000. */
1356 if (dict_size(nickserv_handle_dict
) == 1) {
1357 hi
->opserv_level
= 1000;
1358 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1361 /* Set their email address. */
1363 nickserv_set_email_addr(hi
, email_addr
);
1365 /* If they need to do email verification, tell them. */
1367 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1369 /* Set registering flag.. */
1370 user
->modes
|= FLAGS_REGISTERING
;
1372 if (nickserv_conf
.sync_log
) {
1373 cryptpass(password
, syncpass
);
1375 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1376 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1379 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1382 /* this wont work if email is required .. */
1383 process_adduser_pending(user
);
1388 static NICKSERV_FUNC(cmd_oregister
)
1390 struct userNode
*settee
= NULL
;
1391 struct handle_info
*hi
;
1392 char* account
= NULL
;
1398 NICKSERV_MIN_PARMS(3);
1402 if (nickserv_conf
.email_required
) {
1403 NICKSERV_MIN_PARMS(4);
1405 if (argc
>= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1406 if (strchr(argv
[4], '@') || argc
>= 6) /* If @, its mask not nick */
1416 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1417 if (strchr(argv
[3], '@') || argc
>= 5) /* If @, its mask not nick */
1426 /* If they passed a nick, look for that user.. */
1427 if (nick
&& !(settee
= GetUserH(nick
))) {
1428 reply("MSG_NICK_UNKNOWN", argv
[4]);
1431 /* If the setee is already authed, we cant add a 2nd account for them.. */
1432 if (settee
&& settee
->handle_info
) {
1433 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1436 /* If there is no default mask in the conf, and they didn't pass a mask,
1437 * but we did find a user by nick, generate the mask */
1439 if (nickserv_conf
.default_hostmask
)
1442 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1444 reply("NSMSG_REGISTER_BAD_NICKMASK");
1449 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1450 return 0; /* error reply handled by above */
1453 nickserv_set_email_addr(hi
, email
);
1456 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1457 string_list_append(hi
->masks
, mask_canonicalized
);
1460 if (nickserv_conf
.sync_log
)
1461 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1466 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1469 struct userNode
*target
;
1470 char *new_mask
= strdup(pretty_mask(mask
));
1471 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1472 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1473 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1478 string_list_append(hi
->ignores
, new_mask
);
1479 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1481 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1482 irc_silence(target
, new_mask
, 1);
1487 static NICKSERV_FUNC(cmd_addignore
)
1489 NICKSERV_MIN_PARMS(2);
1491 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1494 static NICKSERV_FUNC(cmd_oaddignore
)
1496 struct handle_info
*hi
;
1498 NICKSERV_MIN_PARMS(3);
1499 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1502 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1506 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1509 struct userNode
*target
;
1510 char *pmask
= strdup(pretty_mask(del_mask
));
1511 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1512 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1513 char *old_mask
= hi
->ignores
->list
[i
];
1514 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1515 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1516 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1517 irc_silence(target
, old_mask
, 0);
1524 reply("NSMSG_DELMASK_NOT_FOUND");
1528 static NICKSERV_FUNC(cmd_delignore
)
1530 NICKSERV_MIN_PARMS(2);
1531 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1534 static NICKSERV_FUNC(cmd_odelignore
)
1536 struct handle_info
*hi
;
1537 NICKSERV_MIN_PARMS(3);
1538 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1540 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1543 static NICKSERV_FUNC(cmd_handleinfo
)
1546 unsigned int i
, pos
=0, herelen
;
1547 struct userNode
*target
, *next_un
;
1548 struct handle_info
*hi
;
1549 const char *nsmsg_none
;
1552 if (!(hi
= user
->handle_info
)) {
1553 reply("NSMSG_MUST_AUTH");
1556 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1560 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1561 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1563 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1566 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1567 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1569 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1572 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1573 if (HANDLE_FLAGGED(hi
, FROZEN
))
1574 reply("NSMSG_HANDLEINFO_VACATION");
1576 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1577 struct do_not_register
*dnr
;
1578 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1579 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1580 if (!oper_outranks(cmd
, user
, hi
))
1582 } else if (hi
!= user
->handle_info
) {
1583 reply("NSMSG_HANDLEINFO_END");
1587 if (nickserv_conf
.email_enabled
)
1588 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1592 switch (hi
->cookie
->type
) {
1593 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1594 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1595 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1596 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1597 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1603 unsigned long flen
= 1;
1604 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1606 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1607 if (hi
->flags
& 1 << i
)
1608 flags
[flen
++] = handle_flags
[i
];
1610 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1612 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1615 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1616 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1617 || (hi
->opserv_level
> 0)) {
1618 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1621 if (IsHelping(user
) || IsOper(user
))
1626 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1627 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1632 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1634 if (hi
->last_quit_host
[0])
1635 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1637 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1639 if (nickserv_conf
.disable_nicks
) {
1640 /* nicks disabled; don't show anything about registered nicks */
1641 } else if (hi
->nicks
) {
1642 struct nick_info
*ni
, *next_ni
;
1643 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1644 herelen
= strlen(ni
->nick
);
1645 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1647 goto print_nicks_buff
;
1651 memcpy(buff
+pos
, ni
->nick
, herelen
);
1652 pos
+= herelen
; buff
[pos
++] = ' ';
1656 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1661 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1664 if (hi
->masks
->used
) {
1665 for (i
=0; i
< hi
->masks
->used
; i
++) {
1666 herelen
= strlen(hi
->masks
->list
[i
]);
1667 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1669 goto print_mask_buff
;
1671 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1672 pos
+= herelen
; buff
[pos
++] = ' ';
1673 if (i
+1 == hi
->masks
->used
) {
1676 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1681 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1684 if (hi
->ignores
->used
) {
1685 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1686 herelen
= strlen(hi
->ignores
->list
[i
]);
1687 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1689 goto print_ignore_buff
;
1691 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1692 pos
+= herelen
; buff
[pos
++] = ' ';
1693 if (i
+1 == hi
->ignores
->used
) {
1696 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1701 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1705 struct userData
*channel
, *next
;
1708 for (channel
= hi
->channels
; channel
; channel
= next
) {
1709 next
= channel
->u_next
;
1710 name
= channel
->channel
->channel
->name
;
1711 herelen
= strlen(name
);
1712 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1714 goto print_chans_buff
;
1716 if (IsUserSuspended(channel
))
1718 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1722 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1727 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1730 for (target
= hi
->users
; target
; target
= next_un
) {
1731 herelen
= strlen(target
->nick
);
1732 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1734 goto print_cnick_buff
;
1736 next_un
= target
->next_authed
;
1738 memcpy(buff
+pos
, target
->nick
, herelen
);
1739 pos
+= herelen
; buff
[pos
++] = ' ';
1743 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1748 reply("NSMSG_HANDLEINFO_END");
1752 static NICKSERV_FUNC(cmd_userinfo
)
1754 struct userNode
*target
;
1756 NICKSERV_MIN_PARMS(2);
1757 if (!(target
= GetUserH(argv
[1]))) {
1758 reply("MSG_NICK_UNKNOWN", argv
[1]);
1761 if (target
->handle_info
)
1762 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1764 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1768 static NICKSERV_FUNC(cmd_nickinfo
)
1770 struct nick_info
*ni
;
1772 NICKSERV_MIN_PARMS(2);
1773 if (!(ni
= get_nick_info(argv
[1]))) {
1774 reply("MSG_NICK_UNKNOWN", argv
[1]);
1777 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1781 static NICKSERV_FUNC(cmd_rename_handle
)
1783 struct handle_info
*hi
;
1784 struct userNode
*uNode
;
1788 NICKSERV_MIN_PARMS(3);
1789 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1791 if (!is_valid_handle(argv
[2])) {
1792 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1795 if (get_handle_info(argv
[2])) {
1796 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1799 if(strlen(argv
[2]) > 15)
1801 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1805 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1806 hi
->handle
= strdup(argv
[2]);
1807 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1808 for (nn
=0; nn
<rf_list_used
; nn
++)
1809 rf_list
[nn
](hi
, old_handle
);
1811 if (nickserv_conf
.sync_log
) {
1812 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1813 irc_rename(uNode
, hi
->handle
);
1815 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1818 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1819 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1820 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1826 static failpw_func_t
*failpw_func_list
;
1827 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1830 reg_failpw_func(failpw_func_t func
)
1832 if (failpw_func_used
== failpw_func_size
) {
1833 if (failpw_func_size
) {
1834 failpw_func_size
<<= 1;
1835 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1837 failpw_func_size
= 8;
1838 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1841 failpw_func_list
[failpw_func_used
++] = func
;
1845 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1847 * called by nefariouses enhanced AC login-on-connect code
1850 struct handle_info
*loc_auth(char *handle
, char *password
)
1852 int pw_arg
, used
, maxlogins
;
1855 struct handle_info
*hi
;
1856 struct userNode
*other
;
1858 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1864 /* We don't know the users hostname, or anything because they
1865 * havn't registered yet. So we can only allow LOC if your
1866 * account has *@* as a hostmask.
1868 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1870 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1879 /* Responses from here on look up the language used by the handle they asked about. */
1880 if (!checkpass(password
, hi
->passwd
)) {
1883 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1886 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1887 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1888 if (++used
>= maxlogins
) {
1895 static NICKSERV_FUNC(cmd_auth
)
1897 int pw_arg
, used
, maxlogins
;
1898 struct handle_info
*hi
;
1900 struct userNode
*other
;
1902 if (user
->handle_info
) {
1903 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1906 if (IsStamped(user
)) {
1907 /* Unauthenticated users might still have been stamped
1908 previously and could therefore have a hidden host;
1909 do not allow them to authenticate. */
1910 reply("NSMSG_STAMPED_AUTH");
1914 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1916 } else if (argc
== 2) {
1917 if (nickserv_conf
.disable_nicks
) {
1918 if (!(hi
= get_handle_info(user
->nick
))) {
1919 reply("NSMSG_HANDLE_NOT_FOUND");
1923 /* try to look up their handle from their nick */
1924 struct nick_info
*ni
;
1925 ni
= get_nick_info(user
->nick
);
1927 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1934 reply("MSG_MISSING_PARAMS", argv
[0]);
1935 svccmd_send_help_brief(user
, nickserv
, cmd
);
1939 reply("NSMSG_HANDLE_NOT_FOUND");
1942 /* Responses from here on look up the language used by the handle they asked about. */
1943 passwd
= argv
[pw_arg
];
1944 if (!valid_user_for(user
, hi
)) {
1945 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1946 send_message_type(4, user
, cmd
->parent
->bot
,
1947 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1950 send_message_type(4, user
, cmd
->parent
->bot
,
1951 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1953 argv
[pw_arg
] = "BADMASK";
1956 if (!checkpass(passwd
, hi
->passwd
)) {
1958 send_message_type(4, user
, cmd
->parent
->bot
,
1959 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1960 argv
[pw_arg
] = "BADPASS";
1961 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1962 if (nickserv_conf
.autogag_enabled
) {
1963 if (!user
->auth_policer
.params
) {
1964 user
->auth_policer
.last_req
= now
;
1965 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1967 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1969 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1970 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1971 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1973 argv
[pw_arg
] = "GAGGED";
1978 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1979 send_message_type(4, user
, cmd
->parent
->bot
,
1980 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1981 argv
[pw_arg
] = "SUSPENDED";
1984 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1985 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1986 if (++used
>= maxlogins
) {
1987 send_message_type(4, user
, cmd
->parent
->bot
,
1988 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1990 argv
[pw_arg
] = "MAXLOGINS";
1995 set_user_handle_info(user
, hi
, 1);
1996 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1997 reply("NSMSG_PLEASE_SET_EMAIL");
1998 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1999 reply("NSMSG_WEAK_PASSWORD");
2000 if (hi
->passwd
[0] != '$')
2001 cryptpass(passwd
, hi
->passwd
);
2003 /* If a channel was waiting for this user to auth,
2004 * finish adding them */
2005 process_adduser_pending(user
);
2007 reply("NSMSG_AUTH_SUCCESS");
2010 /* Set +x if autohide is on */
2011 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2012 irc_umode(user
, "+x");
2014 if(!IsOper(user
)) /* If they arnt already opered.. */
2016 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2017 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2019 irc_umode(user
,nickserv_conf
.auto_admin
);
2020 reply("NSMSG_AUTO_OPER_ADMIN");
2022 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2024 irc_umode(user
,nickserv_conf
.auto_oper
);
2025 reply("NSMSG_AUTO_OPER");
2029 /* Wipe out the pass for the logs */
2030 argv
[pw_arg
] = "****";
2034 static allowauth_func_t
*allowauth_func_list
;
2035 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2038 reg_allowauth_func(allowauth_func_t func
)
2040 if (allowauth_func_used
== allowauth_func_size
) {
2041 if (allowauth_func_size
) {
2042 allowauth_func_size
<<= 1;
2043 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2045 allowauth_func_size
= 8;
2046 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2049 allowauth_func_list
[allowauth_func_used
++] = func
;
2052 static NICKSERV_FUNC(cmd_allowauth
)
2054 struct userNode
*target
;
2055 struct handle_info
*hi
;
2058 NICKSERV_MIN_PARMS(2);
2059 if (!(target
= GetUserH(argv
[1]))) {
2060 reply("MSG_NICK_UNKNOWN", argv
[1]);
2063 if (target
->handle_info
) {
2064 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2067 if (IsStamped(target
)) {
2068 /* Unauthenticated users might still have been stamped
2069 previously and could therefore have a hidden host;
2070 do not allow them to authenticate to an account. */
2071 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2076 else if (!(hi
= get_handle_info(argv
[2]))) {
2077 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2081 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2082 reply("MSG_USER_OUTRANKED", hi
->handle
);
2085 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2086 || (hi
->opserv_level
> 0))
2087 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2088 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2091 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2092 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2093 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2094 if (nickserv_conf
.email_enabled
)
2095 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2097 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2098 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2100 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2102 for (n
=0; n
<allowauth_func_used
; n
++)
2103 allowauth_func_list
[n
](user
, target
, hi
);
2107 static NICKSERV_FUNC(cmd_authcookie
)
2109 struct handle_info
*hi
;
2111 NICKSERV_MIN_PARMS(2);
2112 if (user
->handle_info
) {
2113 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2116 if (IsStamped(user
)) {
2117 /* Unauthenticated users might still have been stamped
2118 previously and could therefore have a hidden host;
2119 do not allow them to authenticate to an account. */
2120 reply("NSMSG_STAMPED_AUTHCOOKIE");
2123 if (!(hi
= get_handle_info(argv
[1]))) {
2124 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2127 if (!hi
->email_addr
) {
2128 reply("MSG_SET_EMAIL_ADDR");
2131 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2135 static NICKSERV_FUNC(cmd_delcookie
)
2137 struct handle_info
*hi
;
2139 hi
= user
->handle_info
;
2141 reply("NSMSG_NO_COOKIE");
2144 switch (hi
->cookie
->type
) {
2147 reply("NSMSG_MUST_TIME_OUT");
2150 nickserv_eat_cookie(hi
->cookie
);
2151 reply("NSMSG_ATE_COOKIE");
2157 static NICKSERV_FUNC(cmd_odelcookie
)
2159 struct handle_info
*hi
;
2161 NICKSERV_MIN_PARMS(2);
2163 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2167 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2171 nickserv_eat_cookie(hi
->cookie
);
2172 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2177 static NICKSERV_FUNC(cmd_resetpass
)
2179 struct handle_info
*hi
;
2180 char crypted
[MD5_CRYPT_LENGTH
];
2183 NICKSERV_MIN_PARMS(3);
2184 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2188 if (user
->handle_info
) {
2189 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2192 if (IsStamped(user
)) {
2193 /* Unauthenticated users might still have been stamped
2194 previously and could therefore have a hidden host;
2195 do not allow them to activate an account. */
2196 reply("NSMSG_STAMPED_RESETPASS");
2199 if (!(hi
= get_handle_info(argv
[1]))) {
2200 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2203 if (!hi
->email_addr
) {
2204 reply("MSG_SET_EMAIL_ADDR");
2207 cryptpass(argv
[2], crypted
);
2209 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2213 static NICKSERV_FUNC(cmd_cookie
)
2215 struct handle_info
*hi
;
2218 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2221 NICKSERV_MIN_PARMS(3);
2222 if (!(hi
= get_handle_info(argv
[1]))) {
2223 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2229 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2230 reply("NSMSG_HANDLE_SUSPENDED");
2235 reply("NSMSG_NO_COOKIE");
2239 /* Check validity of operation before comparing cookie to
2240 * prohibit guessing by authed users. */
2241 if (user
->handle_info
2242 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2243 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2244 reply("NSMSG_CANNOT_COOKIE");
2248 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2249 reply("NSMSG_BAD_COOKIE");
2253 switch (hi
->cookie
->type
) {
2255 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2256 set_user_handle_info(user
, hi
, 1);
2257 reply("NSMSG_HANDLE_ACTIVATED");
2258 if (nickserv_conf
.sync_log
)
2259 SyncLog("ACCOUNTACC %s", hi
->handle
);
2261 case PASSWORD_CHANGE
:
2262 set_user_handle_info(user
, hi
, 1);
2263 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2264 reply("NSMSG_PASSWORD_CHANGED");
2265 if (nickserv_conf
.sync_log
)
2266 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2269 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2271 * This should only happen if an OREGISTER was sent. Require
2272 * email must be enabled! - SiRVulcaN
2274 if (nickserv_conf
.sync_log
)
2275 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2277 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2278 reply("NSMSG_EMAIL_CHANGED");
2279 if (nickserv_conf
.sync_log
)
2280 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2283 set_user_handle_info(user
, hi
, 1);
2284 reply("NSMSG_AUTH_SUCCESS");
2287 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2288 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2292 nickserv_eat_cookie(hi
->cookie
);
2294 process_adduser_pending(user
);
2299 static NICKSERV_FUNC(cmd_oregnick
) {
2301 struct handle_info
*target
;
2302 struct nick_info
*ni
;
2304 NICKSERV_MIN_PARMS(3);
2305 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2308 if (!is_registerable_nick(nick
)) {
2309 reply("NSMSG_BAD_NICK", nick
);
2312 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2314 reply("NSMSG_NICK_EXISTS", nick
);
2317 register_nick(nick
, target
);
2318 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2322 static NICKSERV_FUNC(cmd_regnick
) {
2324 struct nick_info
*ni
;
2326 if (!is_registerable_nick(user
->nick
)) {
2327 reply("NSMSG_BAD_NICK", user
->nick
);
2330 /* count their nicks, see if it's too many */
2331 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2332 if (n
>= nickserv_conf
.nicks_per_handle
) {
2333 reply("NSMSG_TOO_MANY_NICKS");
2336 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2338 reply("NSMSG_NICK_EXISTS", user
->nick
);
2341 register_nick(user
->nick
, user
->handle_info
);
2342 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2346 static NICKSERV_FUNC(cmd_pass
)
2348 struct handle_info
*hi
;
2349 const char *old_pass
, *new_pass
;
2351 NICKSERV_MIN_PARMS(3);
2352 hi
= user
->handle_info
;
2356 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2357 if (!checkpass(old_pass
, hi
->passwd
)) {
2358 argv
[1] = "BADPASS";
2359 reply("NSMSG_PASSWORD_INVALID");
2362 cryptpass(new_pass
, hi
->passwd
);
2363 if (nickserv_conf
.sync_log
)
2364 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2366 reply("NSMSG_PASS_SUCCESS");
2371 nickserv_addmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2374 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2375 for (i
=0; i
<hi
->masks
->used
; i
++) {
2376 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2377 reply("NSMSG_ADDMASK_ALREADY", new_mask
);
2382 string_list_append(hi
->masks
, new_mask
);
2383 reply("NSMSG_ADDMASK_SUCCESS", new_mask
);
2387 static NICKSERV_FUNC(cmd_addmask
)
2390 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2391 int res
= nickserv_addmask(cmd
, user
, user
->handle_info
, mask
);
2395 if (!is_gline(argv
[1])) {
2396 reply("NSMSG_MASK_INVALID", argv
[1]);
2399 return nickserv_addmask(cmd
, user
, user
->handle_info
, argv
[1]);
2403 static NICKSERV_FUNC(cmd_oaddmask
)
2405 struct handle_info
*hi
;
2407 NICKSERV_MIN_PARMS(3);
2408 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2410 return nickserv_addmask(cmd
, user
, hi
, argv
[2]);
2414 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2417 for (i
=0; i
<hi
->masks
->used
; i
++) {
2418 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2419 char *old_mask
= hi
->masks
->list
[i
];
2420 if (hi
->masks
->used
== 1) {
2421 reply("NSMSG_DELMASK_NOTLAST");
2424 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2425 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2430 reply("NSMSG_DELMASK_NOT_FOUND");
2434 static NICKSERV_FUNC(cmd_delmask
)
2436 NICKSERV_MIN_PARMS(2);
2437 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1]);
2440 static NICKSERV_FUNC(cmd_odelmask
)
2442 struct handle_info
*hi
;
2443 NICKSERV_MIN_PARMS(3);
2444 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2446 return nickserv_delmask(cmd
, user
, hi
, argv
[2]);
2450 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2451 unsigned int nn
, add
= 1, pos
;
2452 unsigned long added
, removed
, flag
;
2454 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2456 case '+': add
= 1; break;
2457 case '-': add
= 0; break;
2459 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2460 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2463 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2464 /* cheesy avoidance of looking up the flag name.. */
2465 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2468 flag
= 1 << (pos
- 1);
2470 added
|= flag
, removed
&= ~flag
;
2472 removed
|= flag
, added
&= ~flag
;
2477 *premoved
= removed
;
2482 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2484 unsigned long before
, after
, added
, removed
;
2485 struct userNode
*uNode
;
2487 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2488 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2490 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2491 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2493 /* Strip helping flag if they're only a support helper and not
2494 * currently in #support. */
2495 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2496 struct channelList
*schannels
;
2498 schannels
= chanserv_support_channels();
2499 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2500 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2501 if (GetUserMode(schannels
->list
[ii
], uNode
))
2503 if (ii
< schannels
->used
)
2507 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2510 if (after
&& !before
) {
2511 /* Add user to current helper list. */
2512 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2513 userList_append(&curr_helpers
, uNode
);
2514 } else if (!after
&& before
) {
2515 /* Remove user from current helper list. */
2516 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2517 userList_remove(&curr_helpers
, uNode
);
2524 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2528 char *set_display
[] = {
2529 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2530 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2531 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2534 reply("NSMSG_SETTING_LIST");
2535 reply("NSMSG_SETTING_LIST_HEADER");
2537 /* Do this so options are presented in a consistent order. */
2538 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2539 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2540 opt(cmd
, user
, hi
, override
, 0, NULL
);
2541 reply("NSMSG_SETTING_LIST_END");
2544 static NICKSERV_FUNC(cmd_set
)
2546 struct handle_info
*hi
;
2549 hi
= user
->handle_info
;
2551 set_list(cmd
, user
, hi
, 0);
2554 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2555 reply("NSMSG_INVALID_OPTION", argv
[1]);
2558 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2561 static NICKSERV_FUNC(cmd_oset
)
2563 struct handle_info
*hi
;
2566 NICKSERV_MIN_PARMS(2);
2568 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2572 set_list(cmd
, user
, hi
, 0);
2576 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2577 reply("NSMSG_INVALID_OPTION", argv
[2]);
2581 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
2584 static OPTION_FUNC(opt_info
)
2588 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2590 hi
->infoline
= NULL
;
2592 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2596 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2597 reply("NSMSG_SET_INFO", info
);
2601 static OPTION_FUNC(opt_width
)
2604 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2606 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2607 hi
->screen_width
= MIN_LINE_SIZE
;
2608 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2609 hi
->screen_width
= MAX_LINE_SIZE
;
2611 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
2615 static OPTION_FUNC(opt_tablewidth
)
2618 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2620 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2621 hi
->table_width
= MIN_LINE_SIZE
;
2622 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2623 hi
->table_width
= MAX_LINE_SIZE
;
2625 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2629 static OPTION_FUNC(opt_color
)
2632 if (enabled_string(argv
[1]))
2633 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2634 else if (disabled_string(argv
[1]))
2635 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2637 reply("MSG_INVALID_BINARY", argv
[1]);
2642 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2646 static OPTION_FUNC(opt_privmsg
)
2649 if (enabled_string(argv
[1]))
2650 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2651 else if (disabled_string(argv
[1]))
2652 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2654 reply("MSG_INVALID_BINARY", argv
[1]);
2659 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2663 static OPTION_FUNC(opt_autohide
)
2666 if (enabled_string(argv
[1]))
2667 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2668 else if (disabled_string(argv
[1]))
2669 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2671 reply("MSG_INVALID_BINARY", argv
[1]);
2676 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2680 static OPTION_FUNC(opt_style
)
2685 if (!irccasecmp(argv
[1], "Clean"))
2686 hi
->userlist_style
= HI_STYLE_CLEAN
;
2687 else if (!irccasecmp(argv
[1], "Advanced"))
2688 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2689 else if (!irccasecmp(argv
[1], "Classic"))
2690 hi
->userlist_style
= HI_STYLE_CLASSIC
;
2691 else /* Default to normal */
2692 hi
->userlist_style
= HI_STYLE_NORMAL
;
2693 } /* TODO: give error if unknow style is chosen */
2695 switch (hi
->userlist_style
) {
2696 case HI_STYLE_ADVANCED
:
2699 case HI_STYLE_CLASSIC
:
2702 case HI_STYLE_CLEAN
:
2705 case HI_STYLE_NORMAL
:
2710 reply("NSMSG_SET_STYLE", style
);
2714 static OPTION_FUNC(opt_announcements
)
2719 if (enabled_string(argv
[1]))
2720 hi
->announcements
= 'y';
2721 else if (disabled_string(argv
[1]))
2722 hi
->announcements
= 'n';
2723 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2724 hi
->announcements
= '?';
2726 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
2731 switch (hi
->announcements
) {
2732 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2733 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2734 case '?': choice
= "default"; break;
2735 default: choice
= "unknown"; break;
2737 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
2741 static OPTION_FUNC(opt_password
)
2744 reply("NSMSG_USE_CMD_PASS");
2749 cryptpass(argv
[1], hi
->passwd
);
2751 if (nickserv_conf
.sync_log
)
2752 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2754 reply("NSMSG_SET_PASSWORD", "***");
2758 static OPTION_FUNC(opt_flags
)
2761 unsigned int ii
, flen
;
2764 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2769 nickserv_apply_flags(user
, hi
, argv
[1]);
2771 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2772 if (hi
->flags
& (1 << ii
))
2773 flags
[flen
++] = handle_flags
[ii
];
2776 reply("NSMSG_SET_FLAGS", flags
);
2778 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2782 static OPTION_FUNC(opt_email
)
2786 if (!valid_email(argv
[1])) {
2787 reply("NSMSG_BAD_EMAIL_ADDR");
2790 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2791 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2794 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2795 reply("NSMSG_EMAIL_SAME");
2797 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2799 nickserv_set_email_addr(hi
, argv
[1]);
2801 nickserv_eat_cookie(hi
->cookie
);
2802 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2805 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2809 static OPTION_FUNC(opt_maxlogins
)
2811 unsigned char maxlogins
;
2813 maxlogins
= strtoul(argv
[1], NULL
, 0);
2814 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2815 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2818 hi
->maxlogins
= maxlogins
;
2820 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2821 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
2825 static OPTION_FUNC(opt_advanced
)
2828 if (enabled_string(argv
[1]))
2829 HANDLE_SET_FLAG(hi
, ADVANCED
);
2830 else if (disabled_string(argv
[1]))
2831 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
2833 reply("MSG_INVALID_BINARY", argv
[1]);
2838 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
2842 static OPTION_FUNC(opt_language
)
2844 struct language
*lang
;
2846 lang
= language_find(argv
[1]);
2847 if (irccasecmp(lang
->name
, argv
[1]))
2848 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2849 hi
->language
= lang
;
2851 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
2856 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2857 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2859 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2860 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2861 && (user
->handle_info
->opserv_level
< 1000))) {
2862 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2865 if ((user
->handle_info
->opserv_level
< new_level
)
2866 || ((user
->handle_info
->opserv_level
== new_level
)
2867 && (user
->handle_info
->opserv_level
< 1000))) {
2868 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2871 if (user
->handle_info
== target
) {
2872 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2875 if (target
->opserv_level
== new_level
)
2877 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2878 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2879 target
->opserv_level
= new_level
;
2883 static OPTION_FUNC(opt_level
)
2888 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2892 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2893 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
2897 static OPTION_FUNC(opt_epithet
)
2899 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2901 struct userNode
*target
, *next_un
;
2904 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2908 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2912 if ((epithet
[0] == '*') && !epithet
[1])
2915 hi
->epithet
= strdup(epithet
);
2917 for (target
= hi
->users
; target
; target
= next_un
) {
2918 irc_swhois(nickserv
, target
, hi
->epithet
);
2920 next_un
= target
->next_authed
;
2925 reply("NSMSG_SET_EPITHET", hi
->epithet
);
2927 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2931 static OPTION_FUNC(opt_title
)
2937 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2939 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2944 if(!strcmp(title
, "*")) {
2946 hi
->fakehost
= NULL
;
2949 if (strchr(title
, '.')) {
2950 reply("NSMSG_TITLE_INVALID");
2953 /* Alphanumeric titles only. */
2954 for(sptr
= title
; *sptr
; sptr
++) {
2955 if(!isalnum(*sptr
) && *sptr
!= '-') {
2956 reply("NSMSG_TITLE_INVALID");
2960 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2961 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2962 reply("NSMSG_TITLE_TRUNCATED");
2966 hi
->fakehost
= malloc(strlen(title
)+2);
2967 hi
->fakehost
[0] = '.';
2968 strcpy(hi
->fakehost
+1, title
);
2971 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2972 title
= hi
->fakehost
+ 1;
2974 /* If theres no title set then the default title will therefore
2975 be the first part of hidden_host in x3.conf.example, so for
2976 consistency with opt_fakehost we will print this here */
2977 char *hs
, *hidden_suffix
, *rest
;
2979 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
2980 hidden_suffix
= strdup(hs
);
2982 /* Yes we do this twice */
2983 rest
= strrchr(hidden_suffix
, '.');
2985 rest
= strrchr(hidden_suffix
, '.');
2988 title
= hidden_suffix
;
2992 none
= user_find_message(user
, "MSG_NONE");
2993 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
2998 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3002 // check for a dot in the vhost
3003 if(strchr(vhost
, '.') == NULL
) {
3004 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3008 // check for a @ in the vhost
3009 if(strchr(vhost
, '@') != NULL
) {
3010 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3014 // check for denied words, inspired by monk at paki.sex
3015 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3016 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3017 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3022 // check for ircu's HOSTLEN length.
3023 if(strlen(vhost
) >= HOSTLEN
) {
3024 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3028 /* This can be handled by the regex now if desired.
3029 if (vhost[strspn(vhost, "0123456789.")]) {
3030 hostname = vhost + strlen(vhost);
3031 for (depth = 1; depth && (hostname > vhost); depth--) {
3033 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3036 if (*hostname == '.') hostname++; * advance past last dot we saw *
3037 if(strlen(hostname) > 4) {
3038 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3043 /* test either regex or as valid handle */
3044 if (nickserv_conf
.valid_fakehost_regex_set
) {
3045 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3048 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3049 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3051 if(err
== REG_NOMATCH
) {
3052 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3061 static OPTION_FUNC(opt_fakehost
)
3065 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3067 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3072 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3073 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3076 if (!strcmp(fake
, "*")) {
3079 hi
->fakehost
= NULL
;
3082 else if (!check_vhost(argv
[1], user
, cmd
)) {
3083 /* check_vhost takes care of error reply */
3089 hi
->fakehost
= strdup(fake
);
3092 fake
= hi
->fakehost
;
3094 fake
= generate_fakehost(hi
);
3096 /* Tell them we set the host */
3098 fake
= user_find_message(user
, "MSG_NONE");
3099 reply("NSMSG_SET_FAKEHOST", fake
);
3103 static OPTION_FUNC(opt_note
)
3106 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3111 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3116 if ((text
[0] == '*') && !text
[1])
3119 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3124 reply("NSMSG_SET_NOTE", hi
->note
->note
);
3128 static NICKSERV_FUNC(cmd_reclaim
)
3130 struct handle_info
*hi
;
3131 struct nick_info
*ni
;
3132 struct userNode
*victim
;
3134 NICKSERV_MIN_PARMS(2);
3135 hi
= user
->handle_info
;
3136 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3138 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3141 if (ni
->owner
!= user
->handle_info
) {
3142 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3145 victim
= GetUserH(ni
->nick
);
3147 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3150 if (victim
== user
) {
3151 reply("NSMSG_NICK_USER_YOU");
3154 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3155 switch (nickserv_conf
.reclaim_action
) {
3156 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3157 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3158 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3159 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3164 static NICKSERV_FUNC(cmd_unregnick
)
3167 struct handle_info
*hi
;
3168 struct nick_info
*ni
;
3170 hi
= user
->handle_info
;
3171 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3172 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3174 reply("NSMSG_UNKNOWN_NICK", nick
);
3177 if (hi
!= ni
->owner
) {
3178 reply("NSMSG_NOT_YOUR_NICK", nick
);
3181 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3186 static NICKSERV_FUNC(cmd_ounregnick
)
3188 struct nick_info
*ni
;
3190 NICKSERV_MIN_PARMS(2);
3191 if (!(ni
= get_nick_info(argv
[1]))) {
3192 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3195 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3196 reply("MSG_USER_OUTRANKED", ni
->nick
);
3199 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3204 static NICKSERV_FUNC(cmd_unregister
)
3206 struct handle_info
*hi
;
3209 NICKSERV_MIN_PARMS(2);
3210 hi
= user
->handle_info
;
3213 if (checkpass(passwd
, hi
->passwd
)) {
3214 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3217 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3218 reply("NSMSG_PASSWORD_INVALID");
3223 static NICKSERV_FUNC(cmd_ounregister
)
3225 struct handle_info
*hi
;
3227 NICKSERV_MIN_PARMS(2);
3228 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
3230 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3234 static NICKSERV_FUNC(cmd_status
)
3236 if (nickserv_conf
.disable_nicks
) {
3237 reply("NSMSG_GLOBAL_STATS_NONICK",
3238 dict_size(nickserv_handle_dict
));
3240 if (user
->handle_info
) {
3242 struct nick_info
*ni
;
3243 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3244 reply("NSMSG_HANDLE_STATS", cnt
);
3246 reply("NSMSG_HANDLE_NONE");
3248 reply("NSMSG_GLOBAL_STATS",
3249 dict_size(nickserv_handle_dict
),
3250 dict_size(nickserv_nick_dict
));
3255 static NICKSERV_FUNC(cmd_ghost
)
3257 struct userNode
*target
;
3258 char reason
[MAXLEN
];
3260 NICKSERV_MIN_PARMS(2);
3261 if (!(target
= GetUserH(argv
[1]))) {
3262 reply("MSG_NICK_UNKNOWN", argv
[1]);
3265 if (target
== user
) {
3266 reply("NSMSG_CANNOT_GHOST_SELF");
3269 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3270 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3273 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3274 DelUser(target
, nickserv
, 1, reason
);
3275 reply("NSMSG_GHOST_KILLED", argv
[1]);
3279 static NICKSERV_FUNC(cmd_vacation
)
3281 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3282 reply("NSMSG_ON_VACATION");
3287 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3289 struct handle_info
*hi
;
3292 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3294 saxdb_start_record(ctx
, iter_key(it
), 0);
3295 if (hi
->announcements
!= '?') {
3296 flags
[0] = hi
->announcements
;
3298 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3301 struct handle_cookie
*cookie
= hi
->cookie
;
3304 switch (cookie
->type
) {
3305 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3306 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3307 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3308 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3309 default: type
= NULL
; break;
3312 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3313 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3314 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3316 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3317 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3318 saxdb_end_record(ctx
);
3322 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3324 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3326 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3327 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3328 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3329 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3330 saxdb_end_record(ctx
);
3334 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3338 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3339 if (hi
->flags
& (1 << ii
))
3340 flags
[flen
++] = handle_flags
[ii
];
3342 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3345 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3346 if (hi
->last_quit_host
[0])
3347 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3348 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3349 if (hi
->masks
->used
)
3350 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3351 if (hi
->ignores
->used
)
3352 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3354 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3356 struct string_list
*slist
;
3357 struct nick_info
*ni
;
3359 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3360 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3361 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3365 if (hi
->opserv_level
)
3366 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3367 if (hi
->language
!= lang_C
)
3368 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3369 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3370 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3371 if (hi
->screen_width
)
3372 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3373 if (hi
->table_width
)
3374 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3375 flags
[0] = hi
->userlist_style
;
3377 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3378 saxdb_end_record(ctx
);
3384 static handle_merge_func_t
*handle_merge_func_list
;
3385 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3388 reg_handle_merge_func(handle_merge_func_t func
)
3390 if (handle_merge_func_used
== handle_merge_func_size
) {
3391 if (handle_merge_func_size
) {
3392 handle_merge_func_size
<<= 1;
3393 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3395 handle_merge_func_size
= 8;
3396 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3399 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3402 static NICKSERV_FUNC(cmd_merge
)
3404 struct handle_info
*hi_from
, *hi_to
;
3405 struct userNode
*last_user
;
3406 struct userData
*cList
, *cListNext
;
3407 unsigned int ii
, jj
, n
;
3409 NICKSERV_MIN_PARMS(3);
3411 if (!(hi_from
= get_victim_oper(cmd
, user
, argv
[1])))
3413 if (!(hi_to
= get_victim_oper(cmd
, user
, argv
[2])))
3415 if (hi_to
== hi_from
) {
3416 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3420 for (n
=0; n
<handle_merge_func_used
; n
++)
3421 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3423 /* Append "from" handle's nicks to "to" handle's nick list. */
3425 struct nick_info
*last_ni
;
3426 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3427 last_ni
->next
= hi_from
->nicks
;
3429 while (hi_from
->nicks
) {
3430 hi_from
->nicks
->owner
= hi_to
;
3431 hi_from
->nicks
= hi_from
->nicks
->next
;
3434 /* Merge the hostmasks. */
3435 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3436 char *mask
= hi_from
->masks
->list
[ii
];
3437 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3438 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3440 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3441 string_list_append(hi_to
->masks
, strdup(mask
));
3444 /* Merge the ignores. */
3445 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3446 char *ignore
= hi_from
->ignores
->list
[ii
];
3447 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3448 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3450 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3451 string_list_append(hi_to
->ignores
, strdup(ignore
));
3454 /* Merge the lists of authed users. */
3456 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3457 last_user
->next_authed
= hi_from
->users
;
3459 hi_to
->users
= hi_from
->users
;
3461 /* Repoint the old "from" handle's users. */
3462 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3463 last_user
->handle_info
= hi_to
;
3465 hi_from
->users
= NULL
;
3467 /* Merge channel userlists. */
3468 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3469 struct userData
*cList2
;
3470 cListNext
= cList
->u_next
;
3471 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3472 if (cList
->channel
== cList2
->channel
)
3474 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3475 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
);
3476 /* keep cList2 in hi_to; remove cList from hi_from */
3477 del_channel_user(cList
, 1);
3480 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
);
3481 /* remove the lower-ranking cList2 from hi_to */
3482 del_channel_user(cList2
, 1);
3484 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3486 /* cList needs to be moved from hi_from to hi_to */
3487 cList
->handle
= hi_to
;
3488 /* Remove from linked list for hi_from */
3489 assert(!cList
->u_prev
);
3490 hi_from
->channels
= cList
->u_next
;
3492 cList
->u_next
->u_prev
= cList
->u_prev
;
3493 /* Add to linked list for hi_to */
3494 cList
->u_prev
= NULL
;
3495 cList
->u_next
= hi_to
->channels
;
3496 if (hi_to
->channels
)
3497 hi_to
->channels
->u_prev
= cList
;
3498 hi_to
->channels
= cList
;
3502 /* Do they get an OpServ level promotion? */
3503 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3504 hi_to
->opserv_level
= hi_from
->opserv_level
;
3506 /* What about last seen time? */
3507 if (hi_from
->lastseen
> hi_to
->lastseen
)
3508 hi_to
->lastseen
= hi_from
->lastseen
;
3510 /* Does a fakehost carry over? (This intentionally doesn't set it
3511 * for users previously attached to hi_to. They'll just have to
3514 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3515 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3517 /* Notify of success. */
3518 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3519 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
3520 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3522 /* Unregister the "from" handle. */
3523 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3528 struct nickserv_discrim
{
3529 unsigned int limit
, min_level
, max_level
;
3530 unsigned long flags_on
, flags_off
;
3531 time_t min_registered
, max_registered
;
3533 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3534 const char *nickmask
;
3535 const char *hostmask
;
3536 const char *handlemask
;
3537 const char *emailmask
;
3540 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3542 struct discrim_apply_info
{
3543 struct nickserv_discrim
*discrim
;
3544 discrim_search_func func
;
3545 struct userNode
*source
;
3546 unsigned int matched
;
3549 static struct nickserv_discrim
*
3550 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
3553 struct nickserv_discrim
*discrim
;
3555 discrim
= malloc(sizeof(*discrim
));
3556 memset(discrim
, 0, sizeof(*discrim
));
3557 discrim
->min_level
= 0;
3558 discrim
->max_level
= ~0;
3559 discrim
->limit
= 50;
3560 discrim
->min_registered
= 0;
3561 discrim
->max_registered
= INT_MAX
;
3562 discrim
->lastseen
= now
;
3564 for (i
=0; i
<argc
; i
++) {
3565 if (i
== argc
- 1) {
3566 reply("MSG_MISSING_PARAMS", argv
[i
]);
3569 if (!irccasecmp(argv
[i
], "limit")) {
3570 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3571 } else if (!irccasecmp(argv
[i
], "flags")) {
3572 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3573 } else if (!irccasecmp(argv
[i
], "registered")) {
3574 const char *cmp
= argv
[++i
];
3575 if (cmp
[0] == '<') {
3576 if (cmp
[1] == '=') {
3577 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3579 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3581 } else if (cmp
[0] == '=') {
3582 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3583 } else if (cmp
[0] == '>') {
3584 if (cmp
[1] == '=') {
3585 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3587 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3590 reply("MSG_INVALID_CRITERIA", cmp
);
3592 } else if (!irccasecmp(argv
[i
], "seen")) {
3593 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3594 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3595 discrim
->nickmask
= argv
[++i
];
3596 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3598 if (!irccasecmp(argv
[i
], "exact")) {
3599 if (i
== argc
- 1) {
3600 reply("MSG_MISSING_PARAMS", argv
[i
]);
3603 discrim
->hostmask_type
= EXACT
;
3604 } else if (!irccasecmp(argv
[i
], "subset")) {
3605 if (i
== argc
- 1) {
3606 reply("MSG_MISSING_PARAMS", argv
[i
]);
3609 discrim
->hostmask_type
= SUBSET
;
3610 } else if (!irccasecmp(argv
[i
], "superset")) {
3611 if (i
== argc
- 1) {
3612 reply("MSG_MISSING_PARAMS", argv
[i
]);
3615 discrim
->hostmask_type
= SUPERSET
;
3616 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3617 if (i
== argc
- 1) {
3618 reply("MSG_MISSING_PARAMS", argv
[i
]);
3621 discrim
->hostmask_type
= LASTQUIT
;
3624 discrim
->hostmask_type
= SUPERSET
;
3626 discrim
->hostmask
= argv
[++i
];
3627 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3628 if (!irccasecmp(argv
[++i
], "*")) {
3629 discrim
->handlemask
= 0;
3631 discrim
->handlemask
= argv
[i
];
3633 } else if (!irccasecmp(argv
[i
], "email")) {
3634 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3635 reply("MSG_NO_SEARCH_ACCESS", "email");
3637 } else if (!irccasecmp(argv
[++i
], "*")) {
3638 discrim
->emailmask
= 0;
3640 discrim
->emailmask
= argv
[i
];
3642 } else if (!irccasecmp(argv
[i
], "access")) {
3643 const char *cmp
= argv
[++i
];
3644 if (cmp
[0] == '<') {
3645 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3646 if (cmp
[1] == '=') {
3647 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3649 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3651 } else if (cmp
[0] == '=') {
3652 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3653 } else if (cmp
[0] == '>') {
3654 if (cmp
[1] == '=') {
3655 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3657 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3660 reply("MSG_INVALID_CRITERIA", cmp
);
3663 reply("MSG_INVALID_CRITERIA", argv
[i
]);
3674 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3676 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3677 || (discrim
->flags_off
& hi
->flags
)
3678 || (discrim
->min_registered
> hi
->registered
)
3679 || (discrim
->max_registered
< hi
->registered
)
3680 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3681 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3682 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3683 || (discrim
->min_level
> hi
->opserv_level
)
3684 || (discrim
->max_level
< hi
->opserv_level
)) {
3687 if (discrim
->hostmask
) {
3689 for (i
=0; i
<hi
->masks
->used
; i
++) {
3690 const char *mask
= hi
->masks
->list
[i
];
3691 if ((discrim
->hostmask_type
== SUBSET
)
3692 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3693 else if ((discrim
->hostmask_type
== EXACT
)
3694 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3695 else if ((discrim
->hostmask_type
== SUPERSET
)
3696 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3697 else if ((discrim
->hostmask_type
== LASTQUIT
)
3698 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3700 if (i
==hi
->masks
->used
) return 0;
3702 if (discrim
->nickmask
) {
3703 struct nick_info
*nick
= hi
->nicks
;
3705 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3708 if (!nick
) return 0;
3714 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3716 dict_iterator_t it
, next
;
3717 unsigned int matched
;
3719 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3720 it
&& (matched
< discrim
->limit
);
3722 next
= iter_next(it
);
3723 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3724 dsf(source
, iter_data(it
));
3732 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3734 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3738 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3743 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3745 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3746 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3750 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3752 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3753 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3754 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3755 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3756 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3760 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3762 struct handle_info_list hil
;
3763 struct helpfile_table tbl
;
3768 memset(&hil
, 0, sizeof(hil
));
3769 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3770 struct handle_info
*hi
= iter_data(it
);
3771 if (hi
->opserv_level
)
3772 handle_info_list_append(&hil
, hi
);
3774 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3775 tbl
.length
= hil
.used
+ 1;
3777 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
3778 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3779 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3782 for (ii
= 0; ii
< hil
.used
; ) {
3783 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3784 ary
[0] = hil
.list
[ii
]->handle
;
3785 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3786 tbl
.contents
[++ii
] = ary
;
3788 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3789 /*reply("MSG_MATCH_COUNT", hil.used); */
3790 for (ii
= 0; ii
< hil
.used
; ii
++)
3791 free(tbl
.contents
[ii
]);
3796 static NICKSERV_FUNC(cmd_search
)
3798 struct nickserv_discrim
*discrim
;
3799 discrim_search_func action
;
3800 struct svccmd
*subcmd
;
3801 unsigned int matches
;
3804 NICKSERV_MIN_PARMS(3);
3805 sprintf(buf
, "search %s", argv
[1]);
3806 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3807 if (!irccasecmp(argv
[1], "print"))
3808 action
= search_print_func
;
3809 else if (!irccasecmp(argv
[1], "count"))
3810 action
= search_count_func
;
3811 else if (!irccasecmp(argv
[1], "unregister"))
3812 action
= search_unregister_func
;
3814 reply("NSMSG_INVALID_ACTION", argv
[1]);
3818 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3821 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
3825 if (action
== search_print_func
)
3826 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3827 else if (action
== search_count_func
)
3828 discrim
->limit
= INT_MAX
;
3830 matches
= nickserv_discrim_search(discrim
, action
, user
);
3833 reply("MSG_MATCH_COUNT", matches
);
3835 reply("MSG_NO_MATCHES");
3841 static MODCMD_FUNC(cmd_checkpass
)
3843 struct handle_info
*hi
;
3845 NICKSERV_MIN_PARMS(3);
3846 if (!(hi
= get_handle_info(argv
[1]))) {
3847 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3850 if (checkpass(argv
[2], hi
->passwd
))
3851 reply("CHECKPASS_YES");
3853 reply("CHECKPASS_NO");
3859 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3862 struct string_list
*masks
, *slist
, *ignores
;
3863 struct handle_info
*hi
;
3864 struct userNode
*authed_users
;
3865 struct userData
*channels
;
3866 unsigned long int id
;
3869 char *setter
, *note
;
3872 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3873 id
= str
? strtoul(str
, NULL
, 0) : 0;
3874 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3876 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3879 if ((hi
= get_handle_info(handle
))) {
3880 authed_users
= hi
->users
;
3881 channels
= hi
->channels
;
3883 hi
->channels
= NULL
;
3884 dict_remove(nickserv_handle_dict
, hi
->handle
);
3886 authed_users
= NULL
;
3889 hi
= register_handle(handle
, str
, id
);
3891 hi
->users
= authed_users
;
3892 while (authed_users
) {
3893 authed_users
->handle_info
= hi
;
3894 authed_users
= authed_users
->next_authed
;
3897 hi
->channels
= channels
;
3898 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3899 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3900 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
3901 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
3902 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3903 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3904 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3905 hi
->language
= language_find(str
? str
: "C");
3906 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3907 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3908 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3910 hi
->infoline
= strdup(str
);
3911 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3912 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3913 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3914 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3915 /* We want to read the nicks even if disable_nicks is set. This is so
3916 * that we don't lose the nick data entirely. */
3917 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3919 for (ii
=0; ii
<slist
->used
; ii
++)
3920 register_nick(slist
->list
[ii
], hi
);
3922 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3924 for (ii
=0; str
[ii
]; ii
++)
3925 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3927 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3928 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3929 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3930 hi
->announcements
= str
? str
[0] : '?';
3931 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3932 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3933 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3934 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3935 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3937 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3939 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3940 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3942 nickserv_set_email_addr(hi
, str
);
3943 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3945 hi
->epithet
= strdup(str
);
3946 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3948 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3949 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3950 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3951 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3952 if (setter
&& date
&& note
)
3954 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3959 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3961 hi
->fakehost
= strdup(str
);
3963 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3965 const char *data
, *type
, *expires
, *cookie_str
;
3966 struct handle_cookie
*cookie
;
3968 cookie
= calloc(1, sizeof(*cookie
));
3969 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3970 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3971 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3972 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3973 if (!type
|| !expires
|| !cookie_str
) {
3974 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3977 if (!irccasecmp(type
, KEY_ACTIVATION
))
3978 cookie
->type
= ACTIVATION
;
3979 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3980 cookie
->type
= PASSWORD_CHANGE
;
3981 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3982 cookie
->type
= EMAIL_CHANGE
;
3983 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3984 cookie
->type
= ALLOWAUTH
;
3986 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3989 cookie
->expires
= strtoul(expires
, NULL
, 0);
3990 if (cookie
->expires
< now
)
3993 cookie
->data
= strdup(data
);
3994 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3998 nickserv_bake_cookie(cookie
);
4000 nickserv_free_cookie(cookie
);
4005 nickserv_saxdb_read(dict_t db
) {
4007 struct record_data
*rd
;
4009 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4011 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
4016 static NICKSERV_FUNC(cmd_mergedb
)
4018 struct timeval start
, stop
;
4021 NICKSERV_MIN_PARMS(2);
4022 gettimeofday(&start
, NULL
);
4023 if (!(db
= parse_database(argv
[1]))) {
4024 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4027 nickserv_saxdb_read(db
);
4029 gettimeofday(&stop
, NULL
);
4030 stop
.tv_sec
-= start
.tv_sec
;
4031 stop
.tv_usec
-= start
.tv_usec
;
4032 if (stop
.tv_usec
< 0) {
4034 stop
.tv_usec
+= 1000000;
4036 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4041 expire_handles(UNUSED_ARG(void *data
))
4043 dict_iterator_t it
, next
;
4045 struct handle_info
*hi
;
4047 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4048 next
= iter_next(it
);
4050 if ((hi
->opserv_level
> 0)
4052 || HANDLE_FLAGGED(hi
, FROZEN
)
4053 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4056 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4057 if ((now
- hi
->lastseen
) > expiry
) {
4058 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4059 nickserv_unregister_handle(hi
, NULL
, NULL
);
4063 if (nickserv_conf
.handle_expire_frequency
)
4064 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4068 nickserv_load_dict(const char *fname
)
4072 if (!(file
= fopen(fname
, "r"))) {
4073 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4076 while (!feof(file
)) {
4077 fgets(line
, sizeof(line
), file
);
4080 if (line
[strlen(line
)-1] == '\n')
4081 line
[strlen(line
)-1] = 0;
4082 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4085 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4088 static enum reclaim_action
4089 reclaim_action_from_string(const char *str
) {
4091 return RECLAIM_NONE
;
4092 else if (!irccasecmp(str
, "warn"))
4093 return RECLAIM_WARN
;
4094 else if (!irccasecmp(str
, "svsnick"))
4095 return RECLAIM_SVSNICK
;
4096 else if (!irccasecmp(str
, "kill"))
4097 return RECLAIM_KILL
;
4099 return RECLAIM_NONE
;
4103 nickserv_conf_read(void)
4105 dict_t conf_node
, child
;
4108 struct string_list
*strlist
;
4110 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4111 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4114 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4116 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4117 if (nickserv_conf
.valid_handle_regex_set
)
4118 regfree(&nickserv_conf
.valid_handle_regex
);
4120 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4121 nickserv_conf
.valid_handle_regex_set
= !err
;
4122 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4124 nickserv_conf
.valid_handle_regex_set
= 0;
4126 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4127 if (nickserv_conf
.valid_nick_regex_set
)
4128 regfree(&nickserv_conf
.valid_nick_regex
);
4130 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4131 nickserv_conf
.valid_nick_regex_set
= !err
;
4132 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4134 nickserv_conf
.valid_nick_regex_set
= 0;
4136 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4137 if (nickserv_conf
.valid_fakehost_regex_set
)
4138 regfree(&nickserv_conf
.valid_fakehost_regex
);
4140 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4141 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4142 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4144 nickserv_conf
.valid_fakehost_regex_set
= 0;
4146 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4148 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4149 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4150 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4151 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4152 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4153 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4154 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4155 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4156 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4157 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4158 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4159 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4160 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4161 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4162 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4163 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4164 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4165 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4166 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4167 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4168 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4169 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4170 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4171 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4172 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4174 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4175 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4176 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4178 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4179 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4180 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4182 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4183 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4184 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4185 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4186 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4187 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4188 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4189 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4190 if (!nickserv_conf
.disable_nicks
) {
4191 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4192 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4193 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4194 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4195 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4196 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4197 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4198 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4200 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4201 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4202 const char *key
= iter_key(it
), *value
;
4206 if (!strncasecmp(key
, "uc_", 3))
4207 flag
= toupper(key
[3]);
4208 else if (!strncasecmp(key
, "lc_", 3))
4209 flag
= tolower(key
[3]);
4213 if ((pos
= handle_inverse_flags
[flag
])) {
4214 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4215 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4218 if (nickserv_conf
.weak_password_dict
)
4219 dict_delete(nickserv_conf
.weak_password_dict
);
4220 nickserv_conf
.weak_password_dict
= dict_new();
4221 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4222 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4223 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4224 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4226 nickserv_load_dict(str
);
4227 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4228 if (nickserv
&& str
)
4229 NickChange(nickserv
, str
, 0);
4230 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4231 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4232 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4233 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4234 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4235 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4236 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4237 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4238 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4239 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4240 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4241 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4242 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4243 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4244 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4245 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4246 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4247 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4248 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4249 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4251 free_string_list(nickserv_conf
.denied_fakehost_words
);
4252 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4254 strlist
= string_list_copy(strlist
);
4256 strlist
= alloc_string_list(4);
4257 string_list_append(strlist
, strdup("sex"));
4258 string_list_append(strlist
, strdup("fuck"));
4260 nickserv_conf
.denied_fakehost_words
= strlist
;
4262 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4263 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4265 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4266 nickserv_conf
.auto_oper
= str
? str
: "";
4268 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4269 nickserv_conf
.auto_admin
= str
? str
: "";
4271 str
= conf_get_data("server/network", RECDB_QSTRING
);
4272 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4273 if (!nickserv_conf
.auth_policer_params
) {
4274 nickserv_conf
.auth_policer_params
= policer_params_new();
4275 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4276 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4278 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4279 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4280 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4284 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4286 char newnick
[NICKLEN
+1];
4295 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4297 case RECLAIM_SVSNICK
:
4299 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4300 } while (GetUserH(newnick
));
4301 irc_svsnick(nickserv
, user
, newnick
);
4304 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4305 irc_kill(nickserv
, user
, msg
);
4311 nickserv_reclaim_p(void *data
) {
4312 struct userNode
*user
= data
;
4313 struct nick_info
*ni
= get_nick_info(user
->nick
);
4315 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4319 check_user_nick(struct userNode
*user
) {
4320 struct nick_info
*ni
;
4321 user
->modes
&= ~FLAGS_REGNICK
;
4322 if (!(ni
= get_nick_info(user
->nick
)))
4324 if (user
->handle_info
== ni
->owner
) {
4325 user
->modes
|= FLAGS_REGNICK
;
4329 if (nickserv_conf
.warn_nick_owned
)
4330 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4331 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4333 if (nickserv_conf
.auto_reclaim_delay
)
4334 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4336 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4341 handle_new_user(struct userNode
*user
)
4343 return check_user_nick(user
);
4347 handle_account(struct userNode
*user
, const char *stamp
)
4349 struct handle_info
*hi
;
4352 #ifdef WITH_PROTOCOL_P10
4353 time_t timestamp
= 0;
4355 colon
= strchr(stamp
, ':');
4356 if(colon
&& colon
[1])
4359 timestamp
= atoi(colon
+1);
4361 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4362 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4364 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
);
4368 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4369 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4373 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4376 set_user_handle_info(user
, hi
, 0);
4378 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4383 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4385 struct handle_info
*hi
;
4387 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4388 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4389 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4391 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4392 check_user_nick(user
);
4396 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4398 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4399 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4400 set_user_handle_info(user
, NULL
, 0);
4403 static struct modcmd
*
4404 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4406 if (min_level
> 0) {
4408 sprintf(buf
, "%u", min_level
);
4409 if (must_be_qualified
) {
4410 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4412 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4414 } else if (min_level
== 0) {
4415 if (must_be_qualified
) {
4416 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4418 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4421 if (must_be_qualified
) {
4422 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4424 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4430 nickserv_db_cleanup(void)
4432 unreg_del_user_func(nickserv_remove_user
);
4433 userList_clean(&curr_helpers
);
4434 policer_params_delete(nickserv_conf
.auth_policer_params
);
4435 dict_delete(nickserv_handle_dict
);
4436 dict_delete(nickserv_nick_dict
);
4437 dict_delete(nickserv_opt_dict
);
4438 dict_delete(nickserv_allow_auth_dict
);
4439 dict_delete(nickserv_email_dict
);
4440 dict_delete(nickserv_id_dict
);
4441 dict_delete(nickserv_conf
.weak_password_dict
);
4442 free(auth_func_list
);
4443 free(unreg_func_list
);
4445 free(allowauth_func_list
);
4446 free(handle_merge_func_list
);
4447 free(failpw_func_list
);
4448 if (nickserv_conf
.valid_handle_regex_set
)
4449 regfree(&nickserv_conf
.valid_handle_regex
);
4450 if (nickserv_conf
.valid_nick_regex_set
)
4451 regfree(&nickserv_conf
.valid_nick_regex
);
4455 init_nickserv(const char *nick
)
4457 struct chanNode
*chan
;
4459 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4460 reg_new_user_func(handle_new_user
);
4461 reg_nick_change_func(handle_nick_change
);
4462 reg_del_user_func(nickserv_remove_user
);
4463 reg_account_func(handle_account
);
4465 /* set up handle_inverse_flags */
4466 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4467 for (i
=0; handle_flags
[i
]; i
++) {
4468 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4469 flag_access_levels
[i
] = 0;
4472 conf_register_reload(nickserv_conf_read
);
4473 nickserv_opt_dict
= dict_new();
4474 nickserv_email_dict
= dict_new();
4476 dict_set_free_keys(nickserv_email_dict
, free
);
4477 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4479 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4480 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4481 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4482 * a big pain to disable since its nolonger in the config file. ) -Rubin
4484 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4485 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4486 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4487 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4488 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4489 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4490 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4491 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4492 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4493 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4494 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4495 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4496 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4497 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4498 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4499 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4500 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4501 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4502 if (!nickserv_conf
.disable_nicks
) {
4503 /* nick management commands */
4504 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4505 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4506 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4507 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4508 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4509 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4511 if (nickserv_conf
.email_enabled
) {
4512 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4513 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4514 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4515 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4516 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4517 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4519 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4520 /* ignore commands */
4521 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
4522 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
4523 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
4524 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
4525 /* miscellaneous commands */
4526 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4527 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4528 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4529 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4530 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4532 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4533 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4534 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4535 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4536 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4537 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4538 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4539 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4540 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4541 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4542 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4543 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4544 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4545 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4546 if (nickserv_conf
.titlehost_suffix
) {
4547 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4548 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4550 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4551 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4552 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
4553 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4555 nickserv_handle_dict
= dict_new();
4556 dict_set_free_keys(nickserv_handle_dict
, free
);
4557 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4559 nickserv_id_dict
= dict_new();
4560 dict_set_free_keys(nickserv_id_dict
, free
);
4562 nickserv_nick_dict
= dict_new();
4563 dict_set_free_data(nickserv_nick_dict
, free
);
4565 nickserv_allow_auth_dict
= dict_new();
4567 userList_init(&curr_helpers
);
4570 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4571 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4572 nickserv_service
= service_register(nickserv
);
4574 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4575 reg_exit_func(nickserv_db_cleanup
);
4576 if(nickserv_conf
.handle_expire_frequency
)
4577 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4579 if(autojoin_channels
&& nickserv
) {
4580 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
4581 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
4582 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
4586 message_register_table(msgtab
);