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() */
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." },
373 enum reclaim_action
{
379 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
380 static void nickserv_reclaim_p(void *data
);
383 unsigned int disable_nicks
: 1;
384 unsigned int valid_handle_regex_set
: 1;
385 unsigned int valid_nick_regex_set
: 1;
386 unsigned int valid_fakehost_regex_set
: 1;
387 unsigned int autogag_enabled
: 1;
388 unsigned int email_enabled
: 1;
389 unsigned int email_required
: 1;
390 unsigned int default_hostmask
: 1;
391 unsigned int warn_nick_owned
: 1;
392 unsigned int warn_clone_auth
: 1;
393 unsigned int sync_log
: 1;
394 unsigned long nicks_per_handle
;
395 unsigned long password_min_length
;
396 unsigned long password_min_digits
;
397 unsigned long password_min_upper
;
398 unsigned long password_min_lower
;
399 unsigned long db_backup_frequency
;
400 unsigned long handle_expire_frequency
;
401 unsigned long autogag_duration
;
402 unsigned long email_visible_level
;
403 unsigned long cookie_timeout
;
404 unsigned long handle_expire_delay
;
405 unsigned long nochan_handle_expire_delay
;
406 unsigned long modoper_level
;
407 unsigned long set_epithet_level
;
408 unsigned long set_title_level
;
409 unsigned long set_fakehost_level
;
410 unsigned long handles_per_email
;
411 unsigned long email_search_level
;
412 const char *network_name
;
413 const char *titlehost_suffix
;
414 regex_t valid_handle_regex
;
415 regex_t valid_nick_regex
;
416 regex_t valid_fakehost_regex
;
417 dict_t weak_password_dict
;
418 struct policer_params
*auth_policer_params
;
419 enum reclaim_action reclaim_action
;
420 enum reclaim_action auto_reclaim_action
;
421 unsigned long auto_reclaim_delay
;
422 unsigned char default_maxlogins
;
423 unsigned char hard_maxlogins
;
424 const char *auto_oper
;
425 const char *auto_admin
;
427 struct string_list
*denied_fakehost_words
;
430 /* We have 2^32 unique account IDs to use. */
431 unsigned long int highest_id
= 0;
434 canonicalize_hostmask(char *mask
)
436 char *out
= mask
, *temp
;
437 if ((temp
= strchr(mask
, '!'))) {
439 while (*temp
) *out
++ = *temp
++;
445 static struct handle_note
*
446 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
448 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
450 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
452 memcpy(note
->note
, text
, strlen(text
));
456 static struct handle_info
*
457 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
459 struct handle_info
*hi
;
461 #ifdef WITH_PROTOCOL_BAHAMUT
462 char id_base64
[IDLEN
+ 1];
465 /* Assign a unique account ID to the account; note that 0 is
466 an invalid account ID. 1 is therefore the first account ID. */
468 id
= 1 + highest_id
++;
470 /* Note: highest_id is and must always be the highest ID. */
471 if(id
> highest_id
) {
475 inttobase64(id_base64
, id
, IDLEN
);
477 /* Make sure an account with the same ID doesn't exist. If a
478 duplicate is found, log some details and assign a new one.
479 This should be impossible, but it never hurts to expect it. */
480 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
481 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
487 hi
= calloc(1, sizeof(*hi
));
488 hi
->userlist_style
= HI_DEFAULT_STYLE
;
489 hi
->announcements
= '?';
490 hi
->handle
= strdup(handle
);
491 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
493 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
495 #ifdef WITH_PROTOCOL_BAHAMUT
497 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
504 register_nick(const char *nick
, struct handle_info
*owner
)
506 struct nick_info
*ni
;
507 ni
= malloc(sizeof(struct nick_info
));
508 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
510 ni
->next
= owner
->nicks
;
512 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
516 delete_nick(struct nick_info
*ni
)
518 struct nick_info
*last
, *next
;
519 struct userNode
*user
;
520 /* Check to see if we should mark a user as unregistered. */
521 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
522 user
->modes
&= ~FLAGS_REGNICK
;
525 /* Remove ni from the nick_info linked list. */
526 if (ni
== ni
->owner
->nicks
) {
527 ni
->owner
->nicks
= ni
->next
;
529 last
= ni
->owner
->nicks
;
535 last
->next
= next
->next
;
537 dict_remove(nickserv_nick_dict
, ni
->nick
);
540 static unreg_func_t
*unreg_func_list
;
541 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
544 reg_unreg_func(unreg_func_t func
)
546 if (unreg_func_used
== unreg_func_size
) {
547 if (unreg_func_size
) {
548 unreg_func_size
<<= 1;
549 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
552 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
555 unreg_func_list
[unreg_func_used
++] = func
;
559 nickserv_free_cookie(void *data
)
561 struct handle_cookie
*cookie
= data
;
562 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
563 if (cookie
->data
) free(cookie
->data
);
568 free_handle_info(void *vhi
)
570 struct handle_info
*hi
= vhi
;
572 #ifdef WITH_PROTOCOL_BAHAMUT
575 inttobase64(id
, hi
->id
, IDLEN
);
576 dict_remove(nickserv_id_dict
, id
);
579 free_string_list(hi
->masks
);
580 free_string_list(hi
->ignores
);
584 delete_nick(hi
->nicks
);
590 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
591 nickserv_free_cookie(hi
->cookie
);
593 if (hi
->email_addr
) {
594 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
595 handle_info_list_remove(hil
, hi
);
597 dict_remove(nickserv_email_dict
, hi
->email_addr
);
602 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
605 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
608 struct userNode
*uNode
;
610 for (n
=0; n
<unreg_func_used
; n
++)
611 unreg_func_list
[n
](notify
, hi
);
613 if (nickserv_conf
.sync_log
) {
614 uNode
= GetUserH(hi
->users
->nick
);
618 set_user_handle_info(hi
->users
, NULL
, 0);
621 if (nickserv_conf
.disable_nicks
)
622 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
624 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
627 if (nickserv_conf
.sync_log
)
628 SyncLog("UNREGISTER %s", hi
->handle
);
630 dict_remove(nickserv_handle_dict
, hi
->handle
);
634 get_handle_info(const char *handle
)
636 return dict_find(nickserv_handle_dict
, handle
, 0);
640 get_nick_info(const char *nick
)
642 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
646 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
651 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
652 mn
= channel
->members
.list
[nn
];
653 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
660 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
661 if (!user
->handle_info
) {
663 send_message(user
, bot
, "MSG_AUTHENTICATE");
667 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
669 send_message(user
, bot
, "NSMSG_NO_ACCESS");
673 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
675 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
679 if (user
->handle_info
->opserv_level
< min_level
) {
681 send_message(user
, bot
, "NSMSG_NO_ACCESS");
689 is_valid_handle(const char *handle
)
691 struct userNode
*user
;
692 /* cant register a juped nick/service nick as handle, to prevent confusion */
693 user
= GetUserH(handle
);
694 if (user
&& IsLocal(user
))
696 /* check against maximum length */
697 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
699 /* for consistency, only allow account names that could be nicks */
700 if (!is_valid_nick(handle
))
702 /* disallow account names that look like bad words */
703 if (opserv_bad_channel(handle
))
705 /* test either regex or containing all valid chars */
706 if (nickserv_conf
.valid_handle_regex_set
) {
707 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
710 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
711 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
715 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
720 is_registerable_nick(const char *nick
)
722 /* make sure it could be used as an account name */
723 if (!is_valid_handle(nick
))
726 if (strlen(nick
) > NICKLEN
)
728 /* test either regex or as valid handle */
729 if (nickserv_conf
.valid_nick_regex_set
) {
730 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
733 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
734 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
740 /* this has been replaced with one in tools.c
743 is_valid_email_addr(const char *email)
745 return strchr(email, '@') != NULL;
751 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
753 if (hi
->email_addr
) {
754 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
755 return hi
->email_addr
;
765 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
767 struct handle_info
*hi
;
768 struct userNode
*target
;
772 if (!(hi
= get_handle_info(++name
))) {
773 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
778 if (!(target
= GetUserH(name
))) {
779 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
782 if (IsLocal(target
)) {
783 if (IsService(target
))
784 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
786 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
789 if (!(hi
= target
->handle_info
)) {
790 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
798 oper_outranks(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
) {
799 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
801 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
802 if ((user
->handle_info
->opserv_level
== 1000)
803 || (user
->handle_info
== hi
)
804 || ((user
->handle_info
->opserv_level
== 0)
805 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
806 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
810 reply("MSG_USER_OUTRANKED", hi
->handle
);
815 get_victim_oper(struct svccmd
*cmd
, struct userNode
*user
, const char *target
)
817 struct handle_info
*hi
;
818 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
820 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
821 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
824 return oper_outranks(cmd
, user
, hi
) ? hi
: NULL
;
828 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
832 /* If no hostmasks on the account, allow it. */
833 if (!hi
->masks
->used
)
835 /* If any hostmask matches, allow it. */
836 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
837 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
839 /* If they are allowauthed to this account, allow it (removing the aa). */
840 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
841 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
844 /* The user is not allowed to use this account. */
849 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
852 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
856 if (len
< nickserv_conf
.password_min_length
) {
858 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
861 if (!irccasecmp(pass
, handle
)) {
863 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
866 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
869 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
872 for (i
=0; i
<len
; i
++) {
873 if (isdigit(pass
[i
]))
875 if (isupper(pass
[i
]))
877 if (islower(pass
[i
]))
880 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
881 || (cnt_upper
< nickserv_conf
.password_min_upper
)
882 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
884 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
890 static auth_func_t
*auth_func_list
;
891 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
894 reg_auth_func(auth_func_t func
)
896 if (auth_func_used
== auth_func_size
) {
897 if (auth_func_size
) {
898 auth_func_size
<<= 1;
899 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
902 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
905 auth_func_list
[auth_func_used
++] = func
;
908 static handle_rename_func_t
*rf_list
;
909 static unsigned int rf_list_size
, rf_list_used
;
912 reg_handle_rename_func(handle_rename_func_t func
)
914 if (rf_list_used
== rf_list_size
) {
917 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
920 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
923 rf_list
[rf_list_used
++] = func
;
927 generate_fakehost(struct handle_info
*handle
)
929 extern const char *hidden_host_suffix
;
930 static char buffer
[HOSTLEN
+1];
932 if (!handle
->fakehost
) {
933 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
935 } else if (handle
->fakehost
[0] == '.') {
936 /* A leading dot indicates the stored value is actually a title. */
937 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
940 return handle
->fakehost
;
944 apply_fakehost(struct handle_info
*handle
)
946 struct userNode
*target
;
951 fake
= generate_fakehost(handle
);
952 for (target
= handle
->users
; target
; target
= target
->next_authed
)
953 assign_fakehost(target
, fake
, 1);
956 void send_func_list(struct userNode
*user
)
959 struct handle_info
*old_info
;
961 old_info
= user
->handle_info
;
963 for (n
=0; n
<auth_func_used
; n
++)
964 auth_func_list
[n
](user
, old_info
);
968 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
971 struct handle_info
*old_info
;
973 /* This can happen if somebody uses COOKIE while authed, or if
974 * they re-auth to their current handle (which is silly, but users
976 if (user
->handle_info
== hi
)
979 if (user
->handle_info
) {
980 struct userNode
*other
;
983 userList_remove(&curr_helpers
, user
);
985 /* remove from next_authed linked list */
986 if (user
->handle_info
->users
== user
) {
987 user
->handle_info
->users
= user
->next_authed
;
989 for (other
= user
->handle_info
->users
;
990 other
->next_authed
!= user
;
991 other
= other
->next_authed
) ;
992 other
->next_authed
= user
->next_authed
;
994 /* if nobody left on old handle, and they're not an oper, remove !god */
995 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
996 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
997 /* record them as being last seen at this time */
998 user
->handle_info
->lastseen
= now
;
999 /* and record their hostmask */
1000 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
1002 old_info
= user
->handle_info
;
1003 user
->handle_info
= hi
;
1004 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1005 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1007 if (GetUserH(user
->nick
)) {
1008 for (n
=0; n
<auth_func_used
; n
++)
1009 auth_func_list
[n
](user
, old_info
);
1014 struct nick_info
*ni
;
1016 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1017 if (nickserv_conf
.warn_clone_auth
) {
1018 struct userNode
*other
;
1019 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1020 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1023 user
->next_authed
= hi
->users
;
1027 userList_append(&curr_helpers
, user
);
1029 if (hi
->fakehost
|| old_info
)
1033 #ifdef WITH_PROTOCOL_BAHAMUT
1034 /* Stamp users with their account ID. */
1036 inttobase64(id
, hi
->id
, IDLEN
);
1037 #elif WITH_PROTOCOL_P10
1038 /* Stamp users with their account name. */
1039 char *id
= hi
->handle
;
1041 const char *id
= "???";
1043 if (!nickserv_conf
.disable_nicks
) {
1044 struct nick_info
*ni
;
1045 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1046 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1047 user
->modes
|= FLAGS_REGNICK
;
1052 StampUser(user
, id
, hi
->registered
);
1055 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1056 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1058 /* We cannot clear the user's account ID, unfortunately. */
1059 user
->next_authed
= NULL
;
1063 static struct handle_info
*
1064 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1066 struct handle_info
*hi
;
1067 struct nick_info
*ni
;
1068 char crypted
[MD5_CRYPT_LENGTH
];
1070 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1071 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1075 if(strlen(handle
) > 15)
1077 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1081 if (!is_secure_password(handle
, passwd
, user
))
1084 cryptpass(passwd
, crypted
);
1085 hi
= register_handle(handle
, crypted
, 0);
1086 hi
->masks
= alloc_string_list(1);
1087 hi
->ignores
= alloc_string_list(1);
1089 hi
->language
= lang_C
;
1090 hi
->registered
= now
;
1092 hi
->flags
= HI_DEFAULT_FLAGS
;
1093 if (settee
&& !no_auth
)
1094 set_user_handle_info(settee
, hi
, 1);
1097 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1098 else if (nickserv_conf
.disable_nicks
)
1099 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1100 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1101 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1103 register_nick(user
->nick
, hi
);
1104 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1106 if (settee
&& (user
!= settee
))
1107 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1112 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1114 cookie
->hi
->cookie
= cookie
;
1115 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1118 /* Contributed by the great sneep of afternet ;) */
1119 /* Since this gets used in a URL, we want to avoid stuff that confuses
1120 * email clients such as ] and ?. a-z, 0-9 only.
1122 void genpass(char *str
, int len
)
1127 for(i
= 0; i
< len
; i
++)
1131 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1132 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1140 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1142 struct handle_cookie
*cookie
;
1143 char subject
[128], body
[4096], *misc
;
1144 const char *netname
, *fmt
;
1148 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1152 cookie
= calloc(1, sizeof(*cookie
));
1154 cookie
->type
= type
;
1155 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1157 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1158 /* Adding dedicated password gen function for more control -Rubin */
1159 genpass(cookie
->cookie
, 10);
1161 *inttobase64(cookie->cookie, rand(), 5);
1162 *inttobase64(cookie->cookie+5, rand(), 5);
1165 netname
= nickserv_conf
.network_name
;
1168 switch (cookie
->type
) {
1170 hi
->passwd
[0] = 0; /* invalidate password */
1171 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1172 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1173 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1176 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1178 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1180 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1183 case PASSWORD_CHANGE
:
1184 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1185 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1186 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1188 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1190 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1191 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1194 misc
= hi
->email_addr
;
1195 hi
->email_addr
= cookie
->data
;
1196 #ifdef stupid_verify_old_email
1198 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1199 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1200 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1201 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1202 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1203 sendmail(nickserv
, hi
, subject
, body
, 1);
1204 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1205 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1208 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1209 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1210 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1211 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1212 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1213 sendmail(nickserv
, hi
, subject
, body
, 1);
1215 #ifdef stupid_verify_old_email
1218 hi
->email_addr
= misc
;
1221 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1222 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1223 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1224 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1225 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1228 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1232 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1233 nickserv_bake_cookie(cookie
);
1237 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1239 cookie
->hi
->cookie
= NULL
;
1240 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1241 nickserv_free_cookie(cookie
);
1245 nickserv_free_email_addr(void *data
)
1247 handle_info_list_clean(data
);
1252 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1254 struct handle_info_list
*hil
;
1255 /* Remove from old handle_info_list ... */
1256 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1257 handle_info_list_remove(hil
, hi
);
1258 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1259 hi
->email_addr
= NULL
;
1261 /* Add to the new list.. */
1262 if (new_email_addr
) {
1263 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1264 hil
= calloc(1, sizeof(*hil
));
1265 hil
->tag
= strdup(new_email_addr
);
1266 handle_info_list_init(hil
);
1267 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1269 handle_info_list_append(hil
, hi
);
1270 hi
->email_addr
= hil
->tag
;
1274 static NICKSERV_FUNC(cmd_register
)
1277 struct handle_info
*hi
;
1278 const char *email_addr
, *password
;
1279 char syncpass
[MD5_CRYPT_LENGTH
];
1280 int no_auth
, weblink
;
1282 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1283 /* Require the first handle registered to belong to someone +o. */
1284 reply("NSMSG_REQUIRE_OPER");
1288 if (user
->handle_info
) {
1289 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1293 if (IsRegistering(user
)) {
1294 reply("NSMSG_ALREADY_REGISTERING");
1298 if (IsStamped(user
)) {
1299 /* Unauthenticated users might still have been stamped
1300 previously and could therefore have a hidden host;
1301 do not allow them to register a new account. */
1302 reply("NSMSG_STAMPED_REGISTER");
1306 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1308 if (!is_valid_handle(argv
[1])) {
1309 reply("NSMSG_BAD_HANDLE", argv
[1]);
1314 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1315 struct handle_info_list
*hil
;
1318 /* Remember email address. */
1319 email_addr
= argv
[3];
1321 /* Check that the email address looks valid.. */
1322 if (!valid_email(email_addr
)) {
1323 reply("NSMSG_BAD_EMAIL_ADDR");
1327 /* .. and that we are allowed to send to it. */
1328 if ((str
= sendmail_prohibited_address(email_addr
))) {
1329 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1333 /* If we do email verify, make sure we don't spam the address. */
1334 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1336 for (nn
=0; nn
<hil
->used
; nn
++) {
1337 if (hil
->list
[nn
]->cookie
) {
1338 reply("NSMSG_EMAIL_UNACTIVATED");
1342 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1343 reply("NSMSG_EMAIL_OVERUSED");
1356 /* Webregister hack - send URL instead of IRC cookie
1359 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1363 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1365 /* Add any masks they should get. */
1366 if (nickserv_conf
.default_hostmask
) {
1367 string_list_append(hi
->masks
, strdup("*@*"));
1369 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1370 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1371 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1374 /* If they're the first to register, give them level 1000. */
1375 if (dict_size(nickserv_handle_dict
) == 1) {
1376 hi
->opserv_level
= 1000;
1377 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1380 /* Set their email address. */
1382 nickserv_set_email_addr(hi
, email_addr
);
1384 /* If they need to do email verification, tell them. */
1386 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1388 /* Set registering flag.. */
1389 user
->modes
|= FLAGS_REGISTERING
;
1391 if (nickserv_conf
.sync_log
) {
1392 cryptpass(password
, syncpass
);
1394 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1395 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1398 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1401 /* this wont work if email is required .. */
1402 process_adduser_pending(user
);
1407 static NICKSERV_FUNC(cmd_oregister
)
1409 struct userNode
*settee
= NULL
;
1410 struct handle_info
*hi
;
1411 char* account
= NULL
;
1417 NICKSERV_MIN_PARMS(3);
1421 if (nickserv_conf
.email_required
) {
1422 NICKSERV_MIN_PARMS(4);
1424 if (argc
>= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1425 if (strchr(argv
[4], '@') || argc
>= 6) /* If @, its mask not nick */
1435 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1436 if (strchr(argv
[3], '@') || argc
>= 5) /* If @, its mask not nick */
1445 /* If they passed a nick, look for that user.. */
1446 if (nick
&& !(settee
= GetUserH(nick
))) {
1447 reply("MSG_NICK_UNKNOWN", argv
[4]);
1450 /* If the setee is already authed, we cant add a 2nd account for them.. */
1451 if (settee
&& settee
->handle_info
) {
1452 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1455 /* If there is no default mask in the conf, and they didn't pass a mask,
1456 * but we did find a user by nick, generate the mask */
1458 if (nickserv_conf
.default_hostmask
)
1461 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1463 reply("NSMSG_REGISTER_BAD_NICKMASK");
1468 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1469 return 0; /* error reply handled by above */
1472 nickserv_set_email_addr(hi
, email
);
1475 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1476 string_list_append(hi
->masks
, mask_canonicalized
);
1479 if (nickserv_conf
.sync_log
)
1480 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1485 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1488 struct userNode
*target
;
1489 char *new_mask
= strdup(pretty_mask(mask
));
1490 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1491 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1492 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1497 string_list_append(hi
->ignores
, new_mask
);
1498 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1500 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1501 irc_silence(target
, new_mask
, 1);
1506 static NICKSERV_FUNC(cmd_addignore
)
1508 NICKSERV_MIN_PARMS(2);
1510 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1513 static NICKSERV_FUNC(cmd_oaddignore
)
1515 struct handle_info
*hi
;
1517 NICKSERV_MIN_PARMS(3);
1518 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1521 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1525 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1528 struct userNode
*target
;
1529 char *pmask
= strdup(pretty_mask(del_mask
));
1530 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1531 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1532 char *old_mask
= hi
->ignores
->list
[i
];
1533 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1534 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1535 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1536 irc_silence(target
, old_mask
, 0);
1543 reply("NSMSG_DELMASK_NOT_FOUND");
1547 static NICKSERV_FUNC(cmd_delignore
)
1549 NICKSERV_MIN_PARMS(2);
1550 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1553 static NICKSERV_FUNC(cmd_odelignore
)
1555 struct handle_info
*hi
;
1556 NICKSERV_MIN_PARMS(3);
1557 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1559 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1562 static NICKSERV_FUNC(cmd_handleinfo
)
1565 unsigned int i
, pos
=0, herelen
;
1566 struct userNode
*target
, *next_un
;
1567 struct handle_info
*hi
;
1568 const char *nsmsg_none
;
1571 if (!(hi
= user
->handle_info
)) {
1572 reply("NSMSG_MUST_AUTH");
1575 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1579 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1580 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1582 #ifdef WITH_PROTOCOL_BAHAMUT
1583 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1585 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1588 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1589 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1591 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1594 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1595 if (HANDLE_FLAGGED(hi
, FROZEN
))
1596 reply("NSMSG_HANDLEINFO_VACATION");
1598 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1599 struct do_not_register
*dnr
;
1600 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1601 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1602 if (!oper_outranks(cmd
, user
, hi
))
1604 } else if (hi
!= user
->handle_info
) {
1605 reply("NSMSG_HANDLEINFO_END");
1609 if (nickserv_conf
.email_enabled
)
1610 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1614 switch (hi
->cookie
->type
) {
1615 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1616 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1617 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1618 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1619 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1625 unsigned long flen
= 1;
1626 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1628 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1629 if (hi
->flags
& 1 << i
)
1630 flags
[flen
++] = handle_flags
[i
];
1632 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1634 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1637 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1638 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1639 || (hi
->opserv_level
> 0)) {
1640 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1643 if (IsHelping(user
) || IsOper(user
))
1648 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1649 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1654 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1656 if (hi
->last_quit_host
[0])
1657 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1659 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1661 if (nickserv_conf
.disable_nicks
) {
1662 /* nicks disabled; don't show anything about registered nicks */
1663 } else if (hi
->nicks
) {
1664 struct nick_info
*ni
, *next_ni
;
1665 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1666 herelen
= strlen(ni
->nick
);
1667 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1669 goto print_nicks_buff
;
1673 memcpy(buff
+pos
, ni
->nick
, herelen
);
1674 pos
+= herelen
; buff
[pos
++] = ' ';
1678 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1683 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1686 if (hi
->masks
->used
) {
1687 for (i
=0; i
< hi
->masks
->used
; i
++) {
1688 herelen
= strlen(hi
->masks
->list
[i
]);
1689 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1691 goto print_mask_buff
;
1693 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1694 pos
+= herelen
; buff
[pos
++] = ' ';
1695 if (i
+1 == hi
->masks
->used
) {
1698 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1703 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1706 if (hi
->ignores
->used
) {
1707 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1708 herelen
= strlen(hi
->ignores
->list
[i
]);
1709 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1711 goto print_ignore_buff
;
1713 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1714 pos
+= herelen
; buff
[pos
++] = ' ';
1715 if (i
+1 == hi
->ignores
->used
) {
1718 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1723 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1727 struct userData
*channel
, *next
;
1730 for (channel
= hi
->channels
; channel
; channel
= next
) {
1731 next
= channel
->u_next
;
1732 name
= channel
->channel
->channel
->name
;
1733 herelen
= strlen(name
);
1734 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1736 goto print_chans_buff
;
1738 if (IsUserSuspended(channel
))
1740 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1744 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1749 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1752 for (target
= hi
->users
; target
; target
= next_un
) {
1753 herelen
= strlen(target
->nick
);
1754 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1756 goto print_cnick_buff
;
1758 next_un
= target
->next_authed
;
1760 memcpy(buff
+pos
, target
->nick
, herelen
);
1761 pos
+= herelen
; buff
[pos
++] = ' ';
1765 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1770 reply("NSMSG_HANDLEINFO_END");
1774 static NICKSERV_FUNC(cmd_userinfo
)
1776 struct userNode
*target
;
1778 NICKSERV_MIN_PARMS(2);
1779 if (!(target
= GetUserH(argv
[1]))) {
1780 reply("MSG_NICK_UNKNOWN", argv
[1]);
1783 if (target
->handle_info
)
1784 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1786 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1790 static NICKSERV_FUNC(cmd_nickinfo
)
1792 struct nick_info
*ni
;
1794 NICKSERV_MIN_PARMS(2);
1795 if (!(ni
= get_nick_info(argv
[1]))) {
1796 reply("MSG_NICK_UNKNOWN", argv
[1]);
1799 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1803 static NICKSERV_FUNC(cmd_rename_handle
)
1805 struct handle_info
*hi
;
1806 struct userNode
*uNode
;
1807 char msgbuf
[MAXLEN
], *old_handle
;
1810 NICKSERV_MIN_PARMS(3);
1811 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1813 if (!is_valid_handle(argv
[2])) {
1814 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1817 if (get_handle_info(argv
[2])) {
1818 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1821 if(strlen(argv
[2]) > 15)
1823 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1827 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1828 hi
->handle
= strdup(argv
[2]);
1829 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1830 for (nn
=0; nn
<rf_list_used
; nn
++)
1831 rf_list
[nn
](hi
, old_handle
);
1832 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1835 if (nickserv_conf
.sync_log
) {
1836 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1837 irc_rename(uNode
, hi
->handle
);
1839 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1842 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1843 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1848 static failpw_func_t
*failpw_func_list
;
1849 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1852 reg_failpw_func(failpw_func_t func
)
1854 if (failpw_func_used
== failpw_func_size
) {
1855 if (failpw_func_size
) {
1856 failpw_func_size
<<= 1;
1857 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1859 failpw_func_size
= 8;
1860 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1863 failpw_func_list
[failpw_func_used
++] = func
;
1867 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1869 * called by nefariouses enhanced AC login-on-connect code
1872 struct handle_info
*loc_auth(char *handle
, char *password
)
1874 int pw_arg
, used
, maxlogins
;
1877 struct handle_info
*hi
;
1878 struct userNode
*other
;
1880 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1886 /* We don't know the users hostname, or anything because they
1887 * havn't registered yet. So we can only allow LOC if your
1888 * account has *@* as a hostmask.
1890 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1892 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1901 /* Responses from here on look up the language used by the handle they asked about. */
1902 if (!checkpass(password
, hi
->passwd
)) {
1905 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1908 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1909 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1910 if (++used
>= maxlogins
) {
1917 static NICKSERV_FUNC(cmd_auth
)
1919 int pw_arg
, used
, maxlogins
;
1920 struct handle_info
*hi
;
1922 struct userNode
*other
;
1924 if (user
->handle_info
) {
1925 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1928 if (IsStamped(user
)) {
1929 /* Unauthenticated users might still have been stamped
1930 previously and could therefore have a hidden host;
1931 do not allow them to authenticate. */
1932 reply("NSMSG_STAMPED_AUTH");
1936 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1938 } else if (argc
== 2) {
1939 if (nickserv_conf
.disable_nicks
) {
1940 if (!(hi
= get_handle_info(user
->nick
))) {
1941 reply("NSMSG_HANDLE_NOT_FOUND");
1945 /* try to look up their handle from their nick */
1946 struct nick_info
*ni
;
1947 ni
= get_nick_info(user
->nick
);
1949 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1956 reply("MSG_MISSING_PARAMS", argv
[0]);
1957 svccmd_send_help_brief(user
, nickserv
, cmd
);
1961 reply("NSMSG_HANDLE_NOT_FOUND");
1964 /* Responses from here on look up the language used by the handle they asked about. */
1965 passwd
= argv
[pw_arg
];
1966 if (!valid_user_for(user
, hi
)) {
1967 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1968 send_message_type(4, user
, cmd
->parent
->bot
,
1969 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1972 send_message_type(4, user
, cmd
->parent
->bot
,
1973 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1975 argv
[pw_arg
] = "BADMASK";
1978 if (!checkpass(passwd
, hi
->passwd
)) {
1980 send_message_type(4, user
, cmd
->parent
->bot
,
1981 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1982 argv
[pw_arg
] = "BADPASS";
1983 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1984 if (nickserv_conf
.autogag_enabled
) {
1985 if (!user
->auth_policer
.params
) {
1986 user
->auth_policer
.last_req
= now
;
1987 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1989 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1991 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1992 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1993 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1995 argv
[pw_arg
] = "GAGGED";
2000 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2001 send_message_type(4, user
, cmd
->parent
->bot
,
2002 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2003 argv
[pw_arg
] = "SUSPENDED";
2006 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2007 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2008 if (++used
>= maxlogins
) {
2009 send_message_type(4, user
, cmd
->parent
->bot
,
2010 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2012 argv
[pw_arg
] = "MAXLOGINS";
2017 set_user_handle_info(user
, hi
, 1);
2018 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2019 reply("NSMSG_PLEASE_SET_EMAIL");
2020 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2021 reply("NSMSG_WEAK_PASSWORD");
2022 if (hi
->passwd
[0] != '$')
2023 cryptpass(passwd
, hi
->passwd
);
2025 /* If a channel was waiting for this user to auth,
2026 * finish adding them */
2027 process_adduser_pending(user
);
2029 reply("NSMSG_AUTH_SUCCESS");
2032 /* Set +x if autohide is on */
2033 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2034 irc_umode(user
, "+x");
2036 if(!IsOper(user
)) /* If they arnt already opered.. */
2038 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2039 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2041 irc_umode(user
,nickserv_conf
.auto_admin
);
2042 reply("NSMSG_AUTO_OPER_ADMIN");
2044 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2046 irc_umode(user
,nickserv_conf
.auto_oper
);
2047 reply("NSMSG_AUTO_OPER");
2051 /* Wipe out the pass for the logs */
2052 argv
[pw_arg
] = "****";
2056 static allowauth_func_t
*allowauth_func_list
;
2057 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2060 reg_allowauth_func(allowauth_func_t func
)
2062 if (allowauth_func_used
== allowauth_func_size
) {
2063 if (allowauth_func_size
) {
2064 allowauth_func_size
<<= 1;
2065 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2067 allowauth_func_size
= 8;
2068 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2071 allowauth_func_list
[allowauth_func_used
++] = func
;
2074 static NICKSERV_FUNC(cmd_allowauth
)
2076 struct userNode
*target
;
2077 struct handle_info
*hi
;
2080 NICKSERV_MIN_PARMS(2);
2081 if (!(target
= GetUserH(argv
[1]))) {
2082 reply("MSG_NICK_UNKNOWN", argv
[1]);
2085 if (target
->handle_info
) {
2086 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2089 if (IsStamped(target
)) {
2090 /* Unauthenticated users might still have been stamped
2091 previously and could therefore have a hidden host;
2092 do not allow them to authenticate to an account. */
2093 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2098 else if (!(hi
= get_handle_info(argv
[2]))) {
2099 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2103 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2104 reply("MSG_USER_OUTRANKED", hi
->handle
);
2107 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2108 || (hi
->opserv_level
> 0))
2109 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2110 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2113 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2114 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2115 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2116 if (nickserv_conf
.email_enabled
)
2117 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2119 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2120 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2122 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2124 for (n
=0; n
<allowauth_func_used
; n
++)
2125 allowauth_func_list
[n
](user
, target
, hi
);
2129 static NICKSERV_FUNC(cmd_authcookie
)
2131 struct handle_info
*hi
;
2133 NICKSERV_MIN_PARMS(2);
2134 if (user
->handle_info
) {
2135 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2138 if (IsStamped(user
)) {
2139 /* Unauthenticated users might still have been stamped
2140 previously and could therefore have a hidden host;
2141 do not allow them to authenticate to an account. */
2142 reply("NSMSG_STAMPED_AUTHCOOKIE");
2145 if (!(hi
= get_handle_info(argv
[1]))) {
2146 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2149 if (!hi
->email_addr
) {
2150 reply("MSG_SET_EMAIL_ADDR");
2153 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2157 static NICKSERV_FUNC(cmd_delcookie
)
2159 struct handle_info
*hi
;
2161 hi
= user
->handle_info
;
2163 reply("NSMSG_NO_COOKIE");
2166 switch (hi
->cookie
->type
) {
2169 reply("NSMSG_MUST_TIME_OUT");
2172 nickserv_eat_cookie(hi
->cookie
);
2173 reply("NSMSG_ATE_COOKIE");
2179 static NICKSERV_FUNC(cmd_odelcookie
)
2181 struct handle_info
*hi
;
2183 NICKSERV_MIN_PARMS(2);
2185 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2189 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2193 nickserv_eat_cookie(hi
->cookie
);
2194 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2199 static NICKSERV_FUNC(cmd_resetpass
)
2201 struct handle_info
*hi
;
2202 char crypted
[MD5_CRYPT_LENGTH
];
2205 NICKSERV_MIN_PARMS(3);
2206 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2210 if (user
->handle_info
) {
2211 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2214 if (IsStamped(user
)) {
2215 /* Unauthenticated users might still have been stamped
2216 previously and could therefore have a hidden host;
2217 do not allow them to activate an account. */
2218 reply("NSMSG_STAMPED_RESETPASS");
2221 if (!(hi
= get_handle_info(argv
[1]))) {
2222 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2225 if (!hi
->email_addr
) {
2226 reply("MSG_SET_EMAIL_ADDR");
2229 cryptpass(argv
[2], crypted
);
2231 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2235 static NICKSERV_FUNC(cmd_cookie
)
2237 struct handle_info
*hi
;
2240 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2243 NICKSERV_MIN_PARMS(3);
2244 if (!(hi
= get_handle_info(argv
[1]))) {
2245 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2251 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2252 reply("NSMSG_HANDLE_SUSPENDED");
2257 reply("NSMSG_NO_COOKIE");
2261 /* Check validity of operation before comparing cookie to
2262 * prohibit guessing by authed users. */
2263 if (user
->handle_info
2264 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2265 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2266 reply("NSMSG_CANNOT_COOKIE");
2270 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2271 reply("NSMSG_BAD_COOKIE");
2275 switch (hi
->cookie
->type
) {
2277 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2278 set_user_handle_info(user
, hi
, 1);
2279 reply("NSMSG_HANDLE_ACTIVATED");
2280 if (nickserv_conf
.sync_log
)
2281 SyncLog("ACCOUNTACC %s", hi
->handle
);
2283 case PASSWORD_CHANGE
:
2284 set_user_handle_info(user
, hi
, 1);
2285 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2286 reply("NSMSG_PASSWORD_CHANGED");
2287 if (nickserv_conf
.sync_log
)
2288 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2291 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2293 * This should only happen if an OREGISTER was sent. Require
2294 * email must be enabled! - SiRVulcaN
2296 if (nickserv_conf
.sync_log
)
2297 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2299 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2300 reply("NSMSG_EMAIL_CHANGED");
2301 if (nickserv_conf
.sync_log
)
2302 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2305 set_user_handle_info(user
, hi
, 1);
2306 reply("NSMSG_AUTH_SUCCESS");
2309 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2310 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2314 nickserv_eat_cookie(hi
->cookie
);
2316 process_adduser_pending(user
);
2321 static NICKSERV_FUNC(cmd_oregnick
) {
2323 struct handle_info
*target
;
2324 struct nick_info
*ni
;
2326 NICKSERV_MIN_PARMS(3);
2327 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2330 if (!is_registerable_nick(nick
)) {
2331 reply("NSMSG_BAD_NICK", nick
);
2334 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2336 reply("NSMSG_NICK_EXISTS", nick
);
2339 register_nick(nick
, target
);
2340 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2344 static NICKSERV_FUNC(cmd_regnick
) {
2346 struct nick_info
*ni
;
2348 if (!is_registerable_nick(user
->nick
)) {
2349 reply("NSMSG_BAD_NICK", user
->nick
);
2352 /* count their nicks, see if it's too many */
2353 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2354 if (n
>= nickserv_conf
.nicks_per_handle
) {
2355 reply("NSMSG_TOO_MANY_NICKS");
2358 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2360 reply("NSMSG_NICK_EXISTS", user
->nick
);
2363 register_nick(user
->nick
, user
->handle_info
);
2364 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2368 static NICKSERV_FUNC(cmd_pass
)
2370 struct handle_info
*hi
;
2371 const char *old_pass
, *new_pass
;
2373 NICKSERV_MIN_PARMS(3);
2374 hi
= user
->handle_info
;
2378 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2379 if (!checkpass(old_pass
, hi
->passwd
)) {
2380 argv
[1] = "BADPASS";
2381 reply("NSMSG_PASSWORD_INVALID");
2384 cryptpass(new_pass
, hi
->passwd
);
2385 if (nickserv_conf
.sync_log
)
2386 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2388 reply("NSMSG_PASS_SUCCESS");
2393 nickserv_addmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2396 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2397 for (i
=0; i
<hi
->masks
->used
; i
++) {
2398 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2399 reply("NSMSG_ADDMASK_ALREADY", new_mask
);
2404 string_list_append(hi
->masks
, new_mask
);
2405 reply("NSMSG_ADDMASK_SUCCESS", new_mask
);
2409 static NICKSERV_FUNC(cmd_addmask
)
2412 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2413 int res
= nickserv_addmask(cmd
, user
, user
->handle_info
, mask
);
2417 if (!is_gline(argv
[1])) {
2418 reply("NSMSG_MASK_INVALID", argv
[1]);
2421 return nickserv_addmask(cmd
, user
, user
->handle_info
, argv
[1]);
2425 static NICKSERV_FUNC(cmd_oaddmask
)
2427 struct handle_info
*hi
;
2429 NICKSERV_MIN_PARMS(3);
2430 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2432 return nickserv_addmask(cmd
, user
, hi
, argv
[2]);
2436 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2439 for (i
=0; i
<hi
->masks
->used
; i
++) {
2440 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2441 char *old_mask
= hi
->masks
->list
[i
];
2442 if (hi
->masks
->used
== 1) {
2443 reply("NSMSG_DELMASK_NOTLAST");
2446 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2447 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2452 reply("NSMSG_DELMASK_NOT_FOUND");
2456 static NICKSERV_FUNC(cmd_delmask
)
2458 NICKSERV_MIN_PARMS(2);
2459 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1]);
2462 static NICKSERV_FUNC(cmd_odelmask
)
2464 struct handle_info
*hi
;
2465 NICKSERV_MIN_PARMS(3);
2466 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2468 return nickserv_delmask(cmd
, user
, hi
, argv
[2]);
2472 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2473 unsigned int nn
, add
= 1, pos
;
2474 unsigned long added
, removed
, flag
;
2476 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2478 case '+': add
= 1; break;
2479 case '-': add
= 0; break;
2481 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2482 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2485 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2486 /* cheesy avoidance of looking up the flag name.. */
2487 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2490 flag
= 1 << (pos
- 1);
2492 added
|= flag
, removed
&= ~flag
;
2494 removed
|= flag
, added
&= ~flag
;
2499 *premoved
= removed
;
2504 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2506 unsigned long before
, after
, added
, removed
;
2507 struct userNode
*uNode
;
2509 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2510 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2512 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2513 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2515 /* Strip helping flag if they're only a support helper and not
2516 * currently in #support. */
2517 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2518 struct channelList
*schannels
;
2520 schannels
= chanserv_support_channels();
2521 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2522 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2523 if (GetUserMode(schannels
->list
[ii
], uNode
))
2525 if (ii
< schannels
->used
)
2529 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2532 if (after
&& !before
) {
2533 /* Add user to current helper list. */
2534 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2535 userList_append(&curr_helpers
, uNode
);
2536 } else if (!after
&& before
) {
2537 /* Remove user from current helper list. */
2538 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2539 userList_remove(&curr_helpers
, uNode
);
2546 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2550 char *set_display
[] = {
2551 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2552 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2553 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2556 reply("NSMSG_SETTING_LIST");
2557 reply("NSMSG_SETTING_LIST_HEADER");
2559 /* Do this so options are presented in a consistent order. */
2560 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2561 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2562 opt(cmd
, user
, hi
, override
, 0, NULL
);
2563 reply("NSMSG_SETTING_LIST_END");
2566 static NICKSERV_FUNC(cmd_set
)
2568 struct handle_info
*hi
;
2571 hi
= user
->handle_info
;
2573 set_list(cmd
, user
, hi
, 0);
2576 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2577 reply("NSMSG_INVALID_OPTION", argv
[1]);
2580 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2583 static NICKSERV_FUNC(cmd_oset
)
2585 struct handle_info
*hi
;
2588 NICKSERV_MIN_PARMS(2);
2590 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2594 set_list(cmd
, user
, hi
, 0);
2598 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2599 reply("NSMSG_INVALID_OPTION", argv
[2]);
2603 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
2606 static OPTION_FUNC(opt_info
)
2610 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2612 hi
->infoline
= NULL
;
2614 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2618 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2619 reply("NSMSG_SET_INFO", info
);
2623 static OPTION_FUNC(opt_width
)
2626 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2628 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2629 hi
->screen_width
= MIN_LINE_SIZE
;
2630 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2631 hi
->screen_width
= MAX_LINE_SIZE
;
2633 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
2637 static OPTION_FUNC(opt_tablewidth
)
2640 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2642 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2643 hi
->table_width
= MIN_LINE_SIZE
;
2644 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2645 hi
->table_width
= MAX_LINE_SIZE
;
2647 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2651 static OPTION_FUNC(opt_color
)
2654 if (enabled_string(argv
[1]))
2655 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2656 else if (disabled_string(argv
[1]))
2657 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2659 reply("MSG_INVALID_BINARY", argv
[1]);
2664 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2668 static OPTION_FUNC(opt_privmsg
)
2671 if (enabled_string(argv
[1]))
2672 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2673 else if (disabled_string(argv
[1]))
2674 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2676 reply("MSG_INVALID_BINARY", argv
[1]);
2681 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2685 static OPTION_FUNC(opt_autohide
)
2688 if (enabled_string(argv
[1]))
2689 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2690 else if (disabled_string(argv
[1]))
2691 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2693 reply("MSG_INVALID_BINARY", argv
[1]);
2698 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2702 static OPTION_FUNC(opt_style
)
2707 if (!irccasecmp(argv
[1], "Clean"))
2708 hi
->userlist_style
= HI_STYLE_CLEAN
;
2709 else if (!irccasecmp(argv
[1], "Advanced"))
2710 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2711 else if (!irccasecmp(argv
[1], "Classic"))
2712 hi
->userlist_style
= HI_STYLE_CLASSIC
;
2713 else /* Default to normal */
2714 hi
->userlist_style
= HI_STYLE_NORMAL
;
2715 } /* TODO: give error if unknow style is chosen */
2717 switch (hi
->userlist_style
) {
2718 case HI_STYLE_ADVANCED
:
2721 case HI_STYLE_CLASSIC
:
2724 case HI_STYLE_CLEAN
:
2727 case HI_STYLE_NORMAL
:
2732 reply("NSMSG_SET_STYLE", style
);
2736 static OPTION_FUNC(opt_announcements
)
2741 if (enabled_string(argv
[1]))
2742 hi
->announcements
= 'y';
2743 else if (disabled_string(argv
[1]))
2744 hi
->announcements
= 'n';
2745 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2746 hi
->announcements
= '?';
2748 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
2753 switch (hi
->announcements
) {
2754 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2755 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2756 case '?': choice
= "default"; break;
2757 default: choice
= "unknown"; break;
2759 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
2763 static OPTION_FUNC(opt_password
)
2766 reply("NSMSG_USE_CMD_PASS");
2771 cryptpass(argv
[1], hi
->passwd
);
2773 if (nickserv_conf
.sync_log
)
2774 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2776 reply("NSMSG_SET_PASSWORD", "***");
2780 static OPTION_FUNC(opt_flags
)
2783 unsigned int ii
, flen
;
2786 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2791 nickserv_apply_flags(user
, hi
, argv
[1]);
2793 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2794 if (hi
->flags
& (1 << ii
))
2795 flags
[flen
++] = handle_flags
[ii
];
2798 reply("NSMSG_SET_FLAGS", flags
);
2800 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2804 static OPTION_FUNC(opt_email
)
2808 if (!valid_email(argv
[1])) {
2809 reply("NSMSG_BAD_EMAIL_ADDR");
2812 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2813 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2816 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2817 reply("NSMSG_EMAIL_SAME");
2819 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2821 nickserv_set_email_addr(hi
, argv
[1]);
2823 nickserv_eat_cookie(hi
->cookie
);
2824 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2827 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2831 static OPTION_FUNC(opt_maxlogins
)
2833 unsigned char maxlogins
;
2835 maxlogins
= strtoul(argv
[1], NULL
, 0);
2836 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2837 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2840 hi
->maxlogins
= maxlogins
;
2842 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2843 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
2847 static OPTION_FUNC(opt_advanced
)
2850 if (enabled_string(argv
[1]))
2851 HANDLE_SET_FLAG(hi
, ADVANCED
);
2852 else if (disabled_string(argv
[1]))
2853 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
2855 reply("MSG_INVALID_BINARY", argv
[1]);
2860 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
2864 static OPTION_FUNC(opt_language
)
2866 struct language
*lang
;
2868 lang
= language_find(argv
[1]);
2869 if (irccasecmp(lang
->name
, argv
[1]))
2870 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2871 hi
->language
= lang
;
2873 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
2878 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2879 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2881 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2882 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2883 && (user
->handle_info
->opserv_level
< 1000))) {
2884 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2887 if ((user
->handle_info
->opserv_level
< new_level
)
2888 || ((user
->handle_info
->opserv_level
== new_level
)
2889 && (user
->handle_info
->opserv_level
< 1000))) {
2890 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2893 if (user
->handle_info
== target
) {
2894 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2897 if (target
->opserv_level
== new_level
)
2899 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2900 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2901 target
->opserv_level
= new_level
;
2905 static OPTION_FUNC(opt_level
)
2910 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2914 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2915 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
2919 static OPTION_FUNC(opt_epithet
)
2921 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2923 struct userNode
*target
, *next_un
;
2926 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2930 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2934 if ((epithet
[0] == '*') && !epithet
[1])
2937 hi
->epithet
= strdup(epithet
);
2939 for (target
= hi
->users
; target
; target
= next_un
) {
2940 irc_swhois(nickserv
, target
, hi
->epithet
);
2942 next_un
= target
->next_authed
;
2947 reply("NSMSG_SET_EPITHET", hi
->epithet
);
2949 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2953 static OPTION_FUNC(opt_title
)
2959 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2961 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2966 if(!strcmp(title
, "*")) {
2968 hi
->fakehost
= NULL
;
2971 if (strchr(title
, '.')) {
2972 reply("NSMSG_TITLE_INVALID");
2975 /* Alphanumeric titles only. */
2976 for(sptr
= title
; *sptr
; sptr
++) {
2977 if(!isalnum(*sptr
) && *sptr
!= '-') {
2978 reply("NSMSG_TITLE_INVALID");
2982 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2983 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2984 reply("NSMSG_TITLE_TRUNCATED");
2988 hi
->fakehost
= malloc(strlen(title
)+2);
2989 hi
->fakehost
[0] = '.';
2990 strcpy(hi
->fakehost
+1, title
);
2993 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2994 title
= hi
->fakehost
+ 1;
2996 /* If theres no title set then the default title will therefore
2997 be the first part of hidden_host in x3.conf.example, so for
2998 consistency with opt_fakehost we will print this here */
2999 char *hs
, *hidden_suffix
, *rest
;
3001 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3002 hidden_suffix
= strdup(hs
);
3004 /* Yes we do this twice */
3005 rest
= strrchr(hidden_suffix
, '.');
3007 rest
= strrchr(hidden_suffix
, '.');
3010 title
= hidden_suffix
;
3014 none
= user_find_message(user
, "MSG_NONE");
3015 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3020 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3024 // check for a dot in the vhost
3025 if(strchr(vhost
, '.') == NULL
) {
3026 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3030 // check for a @ in the vhost
3031 if(strchr(vhost
, '@') != NULL
) {
3032 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3036 // check for denied words, inspired by monk at paki.sex
3037 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3038 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3039 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3044 // check for ircu's HOSTLEN length.
3045 if(strlen(vhost
) >= HOSTLEN
) {
3046 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3050 /* This can be handled by the regex now if desired.
3051 if (vhost[strspn(vhost, "0123456789.")]) {
3052 hostname = vhost + strlen(vhost);
3053 for (depth = 1; depth && (hostname > vhost); depth--) {
3055 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3058 if (*hostname == '.') hostname++; * advance past last dot we saw *
3059 if(strlen(hostname) > 4) {
3060 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3065 /* test either regex or as valid handle */
3066 if (nickserv_conf
.valid_fakehost_regex_set
) {
3067 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3070 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3071 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3073 if(err
== REG_NOMATCH
) {
3074 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3083 static OPTION_FUNC(opt_fakehost
)
3087 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3089 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3094 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3095 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3098 if (!strcmp(fake
, "*")) {
3101 hi
->fakehost
= NULL
;
3104 else if (!check_vhost(argv
[1], user
, cmd
)) {
3105 /* check_vhost takes care of error reply */
3111 hi
->fakehost
= strdup(fake
);
3114 fake
= hi
->fakehost
;
3116 fake
= generate_fakehost(hi
);
3118 /* Tell them we set the host */
3120 fake
= user_find_message(user
, "MSG_NONE");
3121 reply("NSMSG_SET_FAKEHOST", fake
);
3125 static OPTION_FUNC(opt_note
)
3128 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3133 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3138 if ((text
[0] == '*') && !text
[1])
3141 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3146 reply("NSMSG_SET_NOTE", hi
->note
->note
);
3150 static NICKSERV_FUNC(cmd_reclaim
)
3152 struct handle_info
*hi
;
3153 struct nick_info
*ni
;
3154 struct userNode
*victim
;
3156 NICKSERV_MIN_PARMS(2);
3157 hi
= user
->handle_info
;
3158 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3160 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3163 if (ni
->owner
!= user
->handle_info
) {
3164 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3167 victim
= GetUserH(ni
->nick
);
3169 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3172 if (victim
== user
) {
3173 reply("NSMSG_NICK_USER_YOU");
3176 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3177 switch (nickserv_conf
.reclaim_action
) {
3178 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3179 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3180 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3181 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3186 static NICKSERV_FUNC(cmd_unregnick
)
3189 struct handle_info
*hi
;
3190 struct nick_info
*ni
;
3192 hi
= user
->handle_info
;
3193 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3194 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3196 reply("NSMSG_UNKNOWN_NICK", nick
);
3199 if (hi
!= ni
->owner
) {
3200 reply("NSMSG_NOT_YOUR_NICK", nick
);
3203 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3208 static NICKSERV_FUNC(cmd_ounregnick
)
3210 struct nick_info
*ni
;
3212 NICKSERV_MIN_PARMS(2);
3213 if (!(ni
= get_nick_info(argv
[1]))) {
3214 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3217 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3218 reply("MSG_USER_OUTRANKED", ni
->nick
);
3221 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3226 static NICKSERV_FUNC(cmd_unregister
)
3228 struct handle_info
*hi
;
3231 NICKSERV_MIN_PARMS(2);
3232 hi
= user
->handle_info
;
3235 if (checkpass(passwd
, hi
->passwd
)) {
3236 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3239 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3240 reply("NSMSG_PASSWORD_INVALID");
3245 static NICKSERV_FUNC(cmd_ounregister
)
3247 struct handle_info
*hi
;
3249 NICKSERV_MIN_PARMS(2);
3250 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
3252 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3256 static NICKSERV_FUNC(cmd_status
)
3258 if (nickserv_conf
.disable_nicks
) {
3259 reply("NSMSG_GLOBAL_STATS_NONICK",
3260 dict_size(nickserv_handle_dict
));
3262 if (user
->handle_info
) {
3264 struct nick_info
*ni
;
3265 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3266 reply("NSMSG_HANDLE_STATS", cnt
);
3268 reply("NSMSG_HANDLE_NONE");
3270 reply("NSMSG_GLOBAL_STATS",
3271 dict_size(nickserv_handle_dict
),
3272 dict_size(nickserv_nick_dict
));
3277 static NICKSERV_FUNC(cmd_ghost
)
3279 struct userNode
*target
;
3280 char reason
[MAXLEN
];
3282 NICKSERV_MIN_PARMS(2);
3283 if (!(target
= GetUserH(argv
[1]))) {
3284 reply("MSG_NICK_UNKNOWN", argv
[1]);
3287 if (target
== user
) {
3288 reply("NSMSG_CANNOT_GHOST_SELF");
3291 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3292 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3295 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3296 DelUser(target
, nickserv
, 1, reason
);
3297 reply("NSMSG_GHOST_KILLED", argv
[1]);
3301 static NICKSERV_FUNC(cmd_vacation
)
3303 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3304 reply("NSMSG_ON_VACATION");
3309 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3311 struct handle_info
*hi
;
3314 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3316 #ifdef WITH_PROTOCOL_BAHAMUT
3319 saxdb_start_record(ctx
, iter_key(it
), 0);
3320 if (hi
->announcements
!= '?') {
3321 flags
[0] = hi
->announcements
;
3323 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3326 struct handle_cookie
*cookie
= hi
->cookie
;
3329 switch (cookie
->type
) {
3330 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3331 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3332 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3333 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3334 default: type
= NULL
; break;
3337 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3338 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3339 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3341 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3342 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3343 saxdb_end_record(ctx
);
3347 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3349 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3351 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3352 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3353 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3354 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3355 saxdb_end_record(ctx
);
3359 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3363 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3364 if (hi
->flags
& (1 << ii
))
3365 flags
[flen
++] = handle_flags
[ii
];
3367 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3369 #ifdef WITH_PROTOCOL_BAHAMUT
3370 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3373 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3374 if (hi
->last_quit_host
[0])
3375 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3376 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3377 if (hi
->masks
->used
)
3378 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3379 if (hi
->ignores
->used
)
3380 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3382 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3384 struct string_list
*slist
;
3385 struct nick_info
*ni
;
3387 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3388 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3389 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3393 if (hi
->opserv_level
)
3394 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3395 if (hi
->language
!= lang_C
)
3396 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3397 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3398 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3399 if (hi
->screen_width
)
3400 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3401 if (hi
->table_width
)
3402 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3403 flags
[0] = hi
->userlist_style
;
3405 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3406 saxdb_end_record(ctx
);
3412 static handle_merge_func_t
*handle_merge_func_list
;
3413 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3416 reg_handle_merge_func(handle_merge_func_t func
)
3418 if (handle_merge_func_used
== handle_merge_func_size
) {
3419 if (handle_merge_func_size
) {
3420 handle_merge_func_size
<<= 1;
3421 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3423 handle_merge_func_size
= 8;
3424 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3427 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3430 static NICKSERV_FUNC(cmd_merge
)
3432 struct handle_info
*hi_from
, *hi_to
;
3433 struct userNode
*last_user
;
3434 struct userData
*cList
, *cListNext
;
3435 unsigned int ii
, jj
, n
;
3436 char buffer
[MAXLEN
];
3438 NICKSERV_MIN_PARMS(3);
3440 if (!(hi_from
= get_victim_oper(cmd
, user
, argv
[1])))
3442 if (!(hi_to
= get_victim_oper(cmd
, user
, argv
[2])))
3444 if (hi_to
== hi_from
) {
3445 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3449 for (n
=0; n
<handle_merge_func_used
; n
++)
3450 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3452 /* Append "from" handle's nicks to "to" handle's nick list. */
3454 struct nick_info
*last_ni
;
3455 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3456 last_ni
->next
= hi_from
->nicks
;
3458 while (hi_from
->nicks
) {
3459 hi_from
->nicks
->owner
= hi_to
;
3460 hi_from
->nicks
= hi_from
->nicks
->next
;
3463 /* Merge the hostmasks. */
3464 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3465 char *mask
= hi_from
->masks
->list
[ii
];
3466 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3467 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3469 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3470 string_list_append(hi_to
->masks
, strdup(mask
));
3473 /* Merge the ignores. */
3474 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3475 char *ignore
= hi_from
->ignores
->list
[ii
];
3476 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3477 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3479 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3480 string_list_append(hi_to
->ignores
, strdup(ignore
));
3483 /* Merge the lists of authed users. */
3485 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3486 last_user
->next_authed
= hi_from
->users
;
3488 hi_to
->users
= hi_from
->users
;
3490 /* Repoint the old "from" handle's users. */
3491 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3492 last_user
->handle_info
= hi_to
;
3494 hi_from
->users
= NULL
;
3496 /* Merge channel userlists. */
3497 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3498 struct userData
*cList2
;
3499 cListNext
= cList
->u_next
;
3500 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3501 if (cList
->channel
== cList2
->channel
)
3503 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3504 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
);
3505 /* keep cList2 in hi_to; remove cList from hi_from */
3506 del_channel_user(cList
, 1);
3509 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
);
3510 /* remove the lower-ranking cList2 from hi_to */
3511 del_channel_user(cList2
, 1);
3513 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3515 /* cList needs to be moved from hi_from to hi_to */
3516 cList
->handle
= hi_to
;
3517 /* Remove from linked list for hi_from */
3518 assert(!cList
->u_prev
);
3519 hi_from
->channels
= cList
->u_next
;
3521 cList
->u_next
->u_prev
= cList
->u_prev
;
3522 /* Add to linked list for hi_to */
3523 cList
->u_prev
= NULL
;
3524 cList
->u_next
= hi_to
->channels
;
3525 if (hi_to
->channels
)
3526 hi_to
->channels
->u_prev
= cList
;
3527 hi_to
->channels
= cList
;
3531 /* Do they get an OpServ level promotion? */
3532 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3533 hi_to
->opserv_level
= hi_from
->opserv_level
;
3535 /* What about last seen time? */
3536 if (hi_from
->lastseen
> hi_to
->lastseen
)
3537 hi_to
->lastseen
= hi_from
->lastseen
;
3539 /* Does a fakehost carry over? (This intentionally doesn't set it
3540 * for users previously attached to hi_to. They'll just have to
3543 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3544 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3546 /* Notify of success. */
3547 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3548 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3549 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3551 /* Unregister the "from" handle. */
3552 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3557 struct nickserv_discrim
{
3558 unsigned int limit
, min_level
, max_level
;
3559 unsigned long flags_on
, flags_off
;
3560 time_t min_registered
, max_registered
;
3562 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3563 const char *nickmask
;
3564 const char *hostmask
;
3565 const char *handlemask
;
3566 const char *emailmask
;
3569 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3571 struct discrim_apply_info
{
3572 struct nickserv_discrim
*discrim
;
3573 discrim_search_func func
;
3574 struct userNode
*source
;
3575 unsigned int matched
;
3578 static struct nickserv_discrim
*
3579 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
3582 struct nickserv_discrim
*discrim
;
3584 discrim
= malloc(sizeof(*discrim
));
3585 memset(discrim
, 0, sizeof(*discrim
));
3586 discrim
->min_level
= 0;
3587 discrim
->max_level
= ~0;
3588 discrim
->limit
= 50;
3589 discrim
->min_registered
= 0;
3590 discrim
->max_registered
= INT_MAX
;
3591 discrim
->lastseen
= now
;
3593 for (i
=0; i
<argc
; i
++) {
3594 if (i
== argc
- 1) {
3595 reply("MSG_MISSING_PARAMS", argv
[i
]);
3598 if (!irccasecmp(argv
[i
], "limit")) {
3599 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3600 } else if (!irccasecmp(argv
[i
], "flags")) {
3601 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3602 } else if (!irccasecmp(argv
[i
], "registered")) {
3603 const char *cmp
= argv
[++i
];
3604 if (cmp
[0] == '<') {
3605 if (cmp
[1] == '=') {
3606 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3608 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3610 } else if (cmp
[0] == '=') {
3611 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3612 } else if (cmp
[0] == '>') {
3613 if (cmp
[1] == '=') {
3614 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3616 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3619 reply("MSG_INVALID_CRITERIA", cmp
);
3621 } else if (!irccasecmp(argv
[i
], "seen")) {
3622 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3623 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3624 discrim
->nickmask
= argv
[++i
];
3625 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3627 if (!irccasecmp(argv
[i
], "exact")) {
3628 if (i
== argc
- 1) {
3629 reply("MSG_MISSING_PARAMS", argv
[i
]);
3632 discrim
->hostmask_type
= EXACT
;
3633 } else if (!irccasecmp(argv
[i
], "subset")) {
3634 if (i
== argc
- 1) {
3635 reply("MSG_MISSING_PARAMS", argv
[i
]);
3638 discrim
->hostmask_type
= SUBSET
;
3639 } else if (!irccasecmp(argv
[i
], "superset")) {
3640 if (i
== argc
- 1) {
3641 reply("MSG_MISSING_PARAMS", argv
[i
]);
3644 discrim
->hostmask_type
= SUPERSET
;
3645 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3646 if (i
== argc
- 1) {
3647 reply("MSG_MISSING_PARAMS", argv
[i
]);
3650 discrim
->hostmask_type
= LASTQUIT
;
3653 discrim
->hostmask_type
= SUPERSET
;
3655 discrim
->hostmask
= argv
[++i
];
3656 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3657 if (!irccasecmp(argv
[++i
], "*")) {
3658 discrim
->handlemask
= 0;
3660 discrim
->handlemask
= argv
[i
];
3662 } else if (!irccasecmp(argv
[i
], "email")) {
3663 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3664 reply("MSG_NO_SEARCH_ACCESS", "email");
3666 } else if (!irccasecmp(argv
[++i
], "*")) {
3667 discrim
->emailmask
= 0;
3669 discrim
->emailmask
= argv
[i
];
3671 } else if (!irccasecmp(argv
[i
], "access")) {
3672 const char *cmp
= argv
[++i
];
3673 if (cmp
[0] == '<') {
3674 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3675 if (cmp
[1] == '=') {
3676 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3678 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3680 } else if (cmp
[0] == '=') {
3681 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3682 } else if (cmp
[0] == '>') {
3683 if (cmp
[1] == '=') {
3684 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3686 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3689 reply("MSG_INVALID_CRITERIA", cmp
);
3692 reply("MSG_INVALID_CRITERIA", argv
[i
]);
3703 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3705 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3706 || (discrim
->flags_off
& hi
->flags
)
3707 || (discrim
->min_registered
> hi
->registered
)
3708 || (discrim
->max_registered
< hi
->registered
)
3709 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3710 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3711 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3712 || (discrim
->min_level
> hi
->opserv_level
)
3713 || (discrim
->max_level
< hi
->opserv_level
)) {
3716 if (discrim
->hostmask
) {
3718 for (i
=0; i
<hi
->masks
->used
; i
++) {
3719 const char *mask
= hi
->masks
->list
[i
];
3720 if ((discrim
->hostmask_type
== SUBSET
)
3721 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3722 else if ((discrim
->hostmask_type
== EXACT
)
3723 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3724 else if ((discrim
->hostmask_type
== SUPERSET
)
3725 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3726 else if ((discrim
->hostmask_type
== LASTQUIT
)
3727 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3729 if (i
==hi
->masks
->used
) return 0;
3731 if (discrim
->nickmask
) {
3732 struct nick_info
*nick
= hi
->nicks
;
3734 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3737 if (!nick
) return 0;
3743 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3745 dict_iterator_t it
, next
;
3746 unsigned int matched
;
3748 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3749 it
&& (matched
< discrim
->limit
);
3751 next
= iter_next(it
);
3752 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3753 dsf(source
, iter_data(it
));
3761 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3763 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3767 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3772 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3774 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3775 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3779 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3781 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3782 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3783 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3784 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3785 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3789 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3791 struct handle_info_list hil
;
3792 struct helpfile_table tbl
;
3797 memset(&hil
, 0, sizeof(hil
));
3798 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3799 struct handle_info
*hi
= iter_data(it
);
3800 if (hi
->opserv_level
)
3801 handle_info_list_append(&hil
, hi
);
3803 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3804 tbl
.length
= hil
.used
+ 1;
3806 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
3807 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3808 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3811 for (ii
= 0; ii
< hil
.used
; ) {
3812 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3813 ary
[0] = hil
.list
[ii
]->handle
;
3814 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3815 tbl
.contents
[++ii
] = ary
;
3817 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3818 /*reply("MSG_MATCH_COUNT", hil.used); */
3819 for (ii
= 0; ii
< hil
.used
; ii
++)
3820 free(tbl
.contents
[ii
]);
3825 static NICKSERV_FUNC(cmd_search
)
3827 struct nickserv_discrim
*discrim
;
3828 discrim_search_func action
;
3829 struct svccmd
*subcmd
;
3830 unsigned int matches
;
3833 NICKSERV_MIN_PARMS(3);
3834 sprintf(buf
, "search %s", argv
[1]);
3835 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3836 if (!irccasecmp(argv
[1], "print"))
3837 action
= search_print_func
;
3838 else if (!irccasecmp(argv
[1], "count"))
3839 action
= search_count_func
;
3840 else if (!irccasecmp(argv
[1], "unregister"))
3841 action
= search_unregister_func
;
3843 reply("NSMSG_INVALID_ACTION", argv
[1]);
3847 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3850 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
3854 if (action
== search_print_func
)
3855 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3856 else if (action
== search_count_func
)
3857 discrim
->limit
= INT_MAX
;
3859 matches
= nickserv_discrim_search(discrim
, action
, user
);
3862 reply("MSG_MATCH_COUNT", matches
);
3864 reply("MSG_NO_MATCHES");
3870 static MODCMD_FUNC(cmd_checkpass
)
3872 struct handle_info
*hi
;
3874 NICKSERV_MIN_PARMS(3);
3875 if (!(hi
= get_handle_info(argv
[1]))) {
3876 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3879 if (checkpass(argv
[2], hi
->passwd
))
3880 reply("CHECKPASS_YES");
3882 reply("CHECKPASS_NO");
3888 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3891 struct string_list
*masks
, *slist
, *ignores
;
3892 struct handle_info
*hi
;
3893 struct userNode
*authed_users
;
3894 struct userData
*channels
;
3895 unsigned long int id
;
3898 char *setter
, *note
;
3901 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3902 id
= str
? strtoul(str
, NULL
, 0) : 0;
3903 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3905 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3908 if ((hi
= get_handle_info(handle
))) {
3909 authed_users
= hi
->users
;
3910 channels
= hi
->channels
;
3912 hi
->channels
= NULL
;
3913 dict_remove(nickserv_handle_dict
, hi
->handle
);
3915 authed_users
= NULL
;
3918 hi
= register_handle(handle
, str
, id
);
3920 hi
->users
= authed_users
;
3921 while (authed_users
) {
3922 authed_users
->handle_info
= hi
;
3923 authed_users
= authed_users
->next_authed
;
3926 hi
->channels
= channels
;
3927 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3928 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3929 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
3930 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
3931 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3932 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3933 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3934 hi
->language
= language_find(str
? str
: "C");
3935 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3936 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3937 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3939 hi
->infoline
= strdup(str
);
3940 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3941 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3942 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3943 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3944 /* We want to read the nicks even if disable_nicks is set. This is so
3945 * that we don't lose the nick data entirely. */
3946 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3948 for (ii
=0; ii
<slist
->used
; ii
++)
3949 register_nick(slist
->list
[ii
], hi
);
3951 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3953 for (ii
=0; str
[ii
]; ii
++)
3954 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3956 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3957 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3958 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3959 hi
->announcements
= str
? str
[0] : '?';
3960 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3961 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3962 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3963 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3964 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3966 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3968 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3969 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3971 nickserv_set_email_addr(hi
, str
);
3972 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3974 hi
->epithet
= strdup(str
);
3975 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3977 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3978 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3979 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3980 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3981 if (setter
&& date
&& note
)
3983 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3988 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3990 hi
->fakehost
= strdup(str
);
3992 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3994 const char *data
, *type
, *expires
, *cookie_str
;
3995 struct handle_cookie
*cookie
;
3997 cookie
= calloc(1, sizeof(*cookie
));
3998 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3999 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4000 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4001 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4002 if (!type
|| !expires
|| !cookie_str
) {
4003 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4006 if (!irccasecmp(type
, KEY_ACTIVATION
))
4007 cookie
->type
= ACTIVATION
;
4008 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4009 cookie
->type
= PASSWORD_CHANGE
;
4010 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4011 cookie
->type
= EMAIL_CHANGE
;
4012 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4013 cookie
->type
= ALLOWAUTH
;
4015 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4018 cookie
->expires
= strtoul(expires
, NULL
, 0);
4019 if (cookie
->expires
< now
)
4022 cookie
->data
= strdup(data
);
4023 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4027 nickserv_bake_cookie(cookie
);
4029 nickserv_free_cookie(cookie
);
4034 nickserv_saxdb_read(dict_t db
) {
4036 struct record_data
*rd
;
4038 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4040 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
4045 static NICKSERV_FUNC(cmd_mergedb
)
4047 struct timeval start
, stop
;
4050 NICKSERV_MIN_PARMS(2);
4051 gettimeofday(&start
, NULL
);
4052 if (!(db
= parse_database(argv
[1]))) {
4053 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4056 nickserv_saxdb_read(db
);
4058 gettimeofday(&stop
, NULL
);
4059 stop
.tv_sec
-= start
.tv_sec
;
4060 stop
.tv_usec
-= start
.tv_usec
;
4061 if (stop
.tv_usec
< 0) {
4063 stop
.tv_usec
+= 1000000;
4065 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4070 expire_handles(UNUSED_ARG(void *data
))
4072 dict_iterator_t it
, next
;
4074 struct handle_info
*hi
;
4076 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4077 next
= iter_next(it
);
4079 if ((hi
->opserv_level
> 0)
4081 || HANDLE_FLAGGED(hi
, FROZEN
)
4082 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4085 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4086 if ((now
- hi
->lastseen
) > expiry
) {
4087 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4088 nickserv_unregister_handle(hi
, NULL
, NULL
);
4092 if (nickserv_conf
.handle_expire_frequency
)
4093 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4097 nickserv_load_dict(const char *fname
)
4101 if (!(file
= fopen(fname
, "r"))) {
4102 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4105 while (!feof(file
)) {
4106 fgets(line
, sizeof(line
), file
);
4109 if (line
[strlen(line
)-1] == '\n')
4110 line
[strlen(line
)-1] = 0;
4111 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4114 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4117 static enum reclaim_action
4118 reclaim_action_from_string(const char *str
) {
4120 return RECLAIM_NONE
;
4121 else if (!irccasecmp(str
, "warn"))
4122 return RECLAIM_WARN
;
4123 else if (!irccasecmp(str
, "svsnick"))
4124 return RECLAIM_SVSNICK
;
4125 else if (!irccasecmp(str
, "kill"))
4126 return RECLAIM_KILL
;
4128 return RECLAIM_NONE
;
4132 nickserv_conf_read(void)
4134 dict_t conf_node
, child
;
4137 struct string_list
*strlist
;
4139 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4140 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4143 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4145 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4146 if (nickserv_conf
.valid_handle_regex_set
)
4147 regfree(&nickserv_conf
.valid_handle_regex
);
4149 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4150 nickserv_conf
.valid_handle_regex_set
= !err
;
4151 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4153 nickserv_conf
.valid_handle_regex_set
= 0;
4155 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4156 if (nickserv_conf
.valid_nick_regex_set
)
4157 regfree(&nickserv_conf
.valid_nick_regex
);
4159 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4160 nickserv_conf
.valid_nick_regex_set
= !err
;
4161 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4163 nickserv_conf
.valid_nick_regex_set
= 0;
4165 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4166 if (nickserv_conf
.valid_fakehost_regex_set
)
4167 regfree(&nickserv_conf
.valid_fakehost_regex
);
4169 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4170 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4171 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4173 nickserv_conf
.valid_fakehost_regex_set
= 0;
4175 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4177 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4178 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4179 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4180 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4181 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4182 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4183 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4184 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4185 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4186 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4187 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4188 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4189 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4190 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4191 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4192 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4193 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4194 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4195 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4196 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4197 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4198 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4199 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4200 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4201 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4203 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4204 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4205 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4207 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4208 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4209 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4211 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4212 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4213 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4214 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4215 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4216 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4217 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4218 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4219 if (!nickserv_conf
.disable_nicks
) {
4220 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4221 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4222 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4223 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4224 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4225 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4226 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4227 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4229 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4230 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4231 const char *key
= iter_key(it
), *value
;
4235 if (!strncasecmp(key
, "uc_", 3))
4236 flag
= toupper(key
[3]);
4237 else if (!strncasecmp(key
, "lc_", 3))
4238 flag
= tolower(key
[3]);
4242 if ((pos
= handle_inverse_flags
[flag
])) {
4243 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4244 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4247 if (nickserv_conf
.weak_password_dict
)
4248 dict_delete(nickserv_conf
.weak_password_dict
);
4249 nickserv_conf
.weak_password_dict
= dict_new();
4250 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4251 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4252 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4253 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4255 nickserv_load_dict(str
);
4256 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4257 if (nickserv
&& str
)
4258 NickChange(nickserv
, str
, 0);
4259 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4260 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4261 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4262 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4263 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4264 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4265 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4266 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4267 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4268 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4269 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4270 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4271 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4272 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4273 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4274 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4275 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4276 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4277 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4278 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4280 free_string_list(nickserv_conf
.denied_fakehost_words
);
4281 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4283 strlist
= string_list_copy(strlist
);
4285 strlist
= alloc_string_list(4);
4286 string_list_append(strlist
, strdup("sex"));
4287 string_list_append(strlist
, strdup("fuck"));
4289 nickserv_conf
.denied_fakehost_words
= strlist
;
4291 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4292 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4294 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4295 nickserv_conf
.auto_oper
= str
? str
: "";
4297 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4298 nickserv_conf
.auto_admin
= str
? str
: "";
4300 str
= conf_get_data("server/network", RECDB_QSTRING
);
4301 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4302 if (!nickserv_conf
.auth_policer_params
) {
4303 nickserv_conf
.auth_policer_params
= policer_params_new();
4304 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4305 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4307 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4308 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4309 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4313 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4315 char newnick
[NICKLEN
+1];
4324 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4326 case RECLAIM_SVSNICK
:
4328 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4329 } while (GetUserH(newnick
));
4330 irc_svsnick(nickserv
, user
, newnick
);
4333 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4334 irc_kill(nickserv
, user
, msg
);
4340 nickserv_reclaim_p(void *data
) {
4341 struct userNode
*user
= data
;
4342 struct nick_info
*ni
= get_nick_info(user
->nick
);
4344 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4348 check_user_nick(struct userNode
*user
) {
4349 struct nick_info
*ni
;
4350 user
->modes
&= ~FLAGS_REGNICK
;
4351 if (!(ni
= get_nick_info(user
->nick
)))
4353 if (user
->handle_info
== ni
->owner
) {
4354 user
->modes
|= FLAGS_REGNICK
;
4358 if (nickserv_conf
.warn_nick_owned
)
4359 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4360 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4362 if (nickserv_conf
.auto_reclaim_delay
)
4363 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4365 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4370 handle_new_user(struct userNode
*user
)
4372 return check_user_nick(user
);
4376 handle_account(struct userNode
*user
, const char *stamp
)
4378 struct handle_info
*hi
;
4381 #ifdef WITH_PROTOCOL_P10
4382 time_t timestamp
= 0;
4384 colon
= strchr(stamp
, ':');
4385 if(colon
&& colon
[1])
4388 timestamp
= atoi(colon
+1);
4390 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4391 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4393 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
);
4397 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4398 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4402 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4405 set_user_handle_info(user
, hi
, 0);
4407 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4412 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4414 struct handle_info
*hi
;
4416 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4417 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4418 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4420 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4421 check_user_nick(user
);
4425 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4427 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4428 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4429 set_user_handle_info(user
, NULL
, 0);
4432 static struct modcmd
*
4433 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4435 if (min_level
> 0) {
4437 sprintf(buf
, "%u", min_level
);
4438 if (must_be_qualified
) {
4439 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4441 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4443 } else if (min_level
== 0) {
4444 if (must_be_qualified
) {
4445 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4447 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4450 if (must_be_qualified
) {
4451 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4453 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4459 nickserv_db_cleanup(void)
4461 unreg_del_user_func(nickserv_remove_user
);
4462 userList_clean(&curr_helpers
);
4463 policer_params_delete(nickserv_conf
.auth_policer_params
);
4464 dict_delete(nickserv_handle_dict
);
4465 dict_delete(nickserv_nick_dict
);
4466 dict_delete(nickserv_opt_dict
);
4467 dict_delete(nickserv_allow_auth_dict
);
4468 dict_delete(nickserv_email_dict
);
4469 dict_delete(nickserv_id_dict
);
4470 dict_delete(nickserv_conf
.weak_password_dict
);
4471 free(auth_func_list
);
4472 free(unreg_func_list
);
4474 free(allowauth_func_list
);
4475 free(handle_merge_func_list
);
4476 free(failpw_func_list
);
4477 if (nickserv_conf
.valid_handle_regex_set
)
4478 regfree(&nickserv_conf
.valid_handle_regex
);
4479 if (nickserv_conf
.valid_nick_regex_set
)
4480 regfree(&nickserv_conf
.valid_nick_regex
);
4484 init_nickserv(const char *nick
)
4486 struct chanNode
*chan
;
4488 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4489 reg_new_user_func(handle_new_user
);
4490 reg_nick_change_func(handle_nick_change
);
4491 reg_del_user_func(nickserv_remove_user
);
4492 reg_account_func(handle_account
);
4494 /* set up handle_inverse_flags */
4495 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4496 for (i
=0; handle_flags
[i
]; i
++) {
4497 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4498 flag_access_levels
[i
] = 0;
4501 conf_register_reload(nickserv_conf_read
);
4502 nickserv_opt_dict
= dict_new();
4503 nickserv_email_dict
= dict_new();
4505 dict_set_free_keys(nickserv_email_dict
, free
);
4506 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4508 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4509 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4510 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4511 * a big pain to disable since its nolonger in the config file. ) -Rubin
4513 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4514 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4515 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4516 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4517 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4518 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4519 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4520 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4521 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4522 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4523 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4524 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4525 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4526 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4527 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4528 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4529 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4530 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4531 if (!nickserv_conf
.disable_nicks
) {
4532 /* nick management commands */
4533 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4534 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4535 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4536 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4537 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4538 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4540 if (nickserv_conf
.email_enabled
) {
4541 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4542 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4543 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4544 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4545 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4546 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4548 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4549 /* ignore commands */
4550 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
4551 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
4552 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
4553 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
4554 /* miscellaneous commands */
4555 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4556 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4557 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4558 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4559 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4561 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4562 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4563 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4564 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4565 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4566 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4567 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4568 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4569 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4570 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4571 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4572 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4573 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4574 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4575 if (nickserv_conf
.titlehost_suffix
) {
4576 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4577 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4579 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4580 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4581 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
4582 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4584 nickserv_handle_dict
= dict_new();
4585 dict_set_free_keys(nickserv_handle_dict
, free
);
4586 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4588 nickserv_id_dict
= dict_new();
4589 dict_set_free_keys(nickserv_id_dict
, free
);
4591 nickserv_nick_dict
= dict_new();
4592 dict_set_free_data(nickserv_nick_dict
, free
);
4594 nickserv_allow_auth_dict
= dict_new();
4596 userList_init(&curr_helpers
);
4599 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4600 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4601 nickserv_service
= service_register(nickserv
);
4603 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4604 reg_exit_func(nickserv_db_cleanup
);
4605 if(nickserv_conf
.handle_expire_frequency
)
4606 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4608 if(autojoin_channels
&& nickserv
) {
4609 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
4610 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
4611 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
4615 message_register_table(msgtab
);