1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
30 #include <tre/regex.h>
32 #define NICKSERV_CONF_NAME "services/nickserv"
34 #define KEY_DISABLE_NICKS "disable_nicks"
35 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
36 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
37 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
38 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
39 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
40 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
41 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
42 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
43 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
44 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
45 #define KEY_VALID_FAKEHOST_REGEX "valid_fakehost_regex"
46 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
47 #define KEY_MODOPER_LEVEL "modoper_level"
48 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
49 #define KEY_SET_TITLE_LEVEL "set_title_level"
50 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
51 #define KEY_DENIED_FAKEHOST_WORDS "denied_fakehost_words"
52 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
53 #define KEY_AUTO_OPER "auto_oper"
54 #define KEY_AUTO_ADMIN "auto_admin"
55 #define KEY_FLAG_LEVELS "flag_levels"
56 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
57 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
58 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
59 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
60 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
61 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
62 #define KEY_DICT_FILE "dict_file"
63 #define KEY_NICK "nick"
64 #define KEY_LANGUAGE "language"
65 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
66 #define KEY_AUTOGAG_DURATION "autogag_duration"
67 #define KEY_AUTH_POLICER "auth_policer"
68 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
69 #define KEY_EMAIL_ENABLED "email_enabled"
70 #define KEY_EMAIL_REQUIRED "email_required"
71 #define KEY_SYNC_LOG "sync_log"
72 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
73 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
74 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
75 #define KEY_DEFAULT_STYLE "default_style"
78 #define KEY_PASSWD "passwd"
79 #define KEY_NICKS "nicks"
80 #define KEY_MASKS "masks"
81 #define KEY_IGNORES "ignores"
82 #define KEY_OPSERV_LEVEL "opserv_level"
83 #define KEY_FLAGS "flags"
84 #define KEY_REGISTER_ON "register"
85 #define KEY_LAST_SEEN "lastseen"
86 #define KEY_INFO "info"
87 #define KEY_USERLIST_STYLE "user_style"
88 #define KEY_SCREEN_WIDTH "screen_width"
89 #define KEY_LAST_AUTHED_HOST "last_authed_host"
90 #define KEY_LAST_QUIT_HOST "last_quit_host"
91 #define KEY_EMAIL_ADDR "email_addr"
92 #define KEY_COOKIE "cookie"
93 #define KEY_COOKIE_DATA "data"
94 #define KEY_COOKIE_TYPE "type"
95 #define KEY_COOKIE_EXPIRES "expires"
96 #define KEY_ACTIVATION "activation"
97 #define KEY_PASSWORD_CHANGE "password change"
98 #define KEY_EMAIL_CHANGE "email change"
99 #define KEY_ALLOWAUTH "allowauth"
100 #define KEY_EPITHET "epithet"
101 #define KEY_TABLE_WIDTH "table_width"
102 #define KEY_ANNOUNCEMENTS "announcements"
103 #define KEY_MAXLOGINS "maxlogins"
104 #define KEY_FAKEHOST "fakehost"
105 #define KEY_NOTE_NOTE "note"
106 #define KEY_NOTE_SETTER "setter"
107 #define KEY_NOTE_DATE "date"
110 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
112 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
113 #define OPTION_FUNC(NAME) int NAME(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
114 typedef OPTION_FUNC(option_func_t
);
116 DEFINE_LIST(handle_info_list
, struct handle_info
*);
118 #define NICKSERV_MIN_PARMS(N) do { \
120 reply("MSG_MISSING_PARAMS", argv[0]); \
121 svccmd_send_help_brief(user, nickserv, cmd); \
125 struct userNode
*nickserv
;
126 struct userList curr_helpers
;
127 const char *handle_flags
= HANDLE_FLAGS
;
129 extern struct string_list
*autojoin_channels
;
130 static struct module *nickserv_module
;
131 static struct service
*nickserv_service
;
132 static struct log_type
*NS_LOG
;
133 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
134 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
135 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
136 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
137 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
138 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
139 static char handle_inverse_flags
[256];
140 static unsigned int flag_access_levels
[32];
141 static const struct message_entry msgtab
[] = {
142 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
143 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
144 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
145 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
146 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
147 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
148 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
149 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
150 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
151 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
152 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
153 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
154 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
155 { "NSMSG_USE_COOKIE_REGISTER", "To activate your account, you must check your email for the \"cookie\" that has been mailed to it. When you have it, use the $bcookie$b command to complete registration." },
156 { "NSMSG_USE_COOKIE_RESETPASS", "A cookie has been mailed to your account's email address. You must check your email and use the $bcookie$b command to confirm the password change." },
157 { "NSMSG_USE_COOKIE_EMAIL_1", "A cookie has been mailed to the new address you requested. To finish setting your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
158 { "NSMSG_USE_COOKIE_EMAIL_2", "A cookie has been generated, and half mailed to each your old and new addresses. To finish changing your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
159 { "NSMSG_USE_COOKIE_AUTH", "A cookie has been generated and sent to your email address. Once you have checked your email and received the cookie, auth using the $bcookie$b command." },
160 { "NSMSG_COOKIE_LIVE", "Account $b%s$b already has a cookie active. Please either finish using that cookie, wait for it to expire, or auth to the account and use the $bdelcookie$b command." },
161 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
162 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
163 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
164 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
165 { "NSMSG_BAD_COOKIE", "That cookie is not the right one. Please make sure you are copying it EXACTLY from the email; it is case-sensitive, so $bABC$b is different from $babc$b." },
166 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
167 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
168 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
169 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
170 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
171 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
172 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
173 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
174 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
175 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
176 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
177 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
178 { "NSMSG_REGISTER_BAD_NICKMASK", "You must provide a hostmask, or online nick to generate one automatically. (or set a default hostmask in the config such as *@*)." },
179 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
180 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
181 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
182 { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%1$s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %1$s)" },
183 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
184 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
185 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
186 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
187 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
188 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
189 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
190 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
191 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
192 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
193 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
194 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
195 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
196 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
197 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
198 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
199 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
200 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
201 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
202 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
203 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
204 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
205 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
206 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
207 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
208 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
209 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
210 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
211 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
212 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
213 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
214 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
215 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
216 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
217 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
218 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
219 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
220 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
221 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
222 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
223 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
224 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
225 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
226 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
227 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
228 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
229 { "NSMSG_WEAK_PASSWORD", "WARNING: You are using a password that is considered weak (easy to guess). It is STRONGLY recommended you change it (now, if not sooner) by typing \"/msg $S@$s PASS oldpass newpass\" (with your current password and a new password)." },
230 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
231 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
232 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
233 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
234 { "NSMSG_AUTH_ALLOWED_MSG", "You may now authenticate to account $b%s$b by typing $b/msg $N@$s auth %s password$b (using your password). If you will be using this computer regularly, please type $b/msg $N addmask$b (AFTER you auth) to permanently add your hostmask." },
235 { "NSMSG_AUTH_ALLOWED_EMAIL", "You may also (after you auth) type $b/msg $N set email user@your.isp$b to set an email address. This will let you use the $bauthcookie$b command to be authenticated in the future." },
236 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
237 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
238 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
239 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
240 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
241 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
242 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
243 { "NSMSG_PASS_SUCCESS", "Password changed." },
244 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
245 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
246 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
247 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
248 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
249 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
250 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
251 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
252 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
253 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
254 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
255 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
256 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
257 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
258 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
259 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
260 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
261 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
262 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
263 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
264 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
265 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
266 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
267 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
268 { "NSMSG_NO_ACCESS", "Access denied." },
269 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
270 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
271 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
272 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
273 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
274 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
275 { "NSMSG_BAD_HANDLE", "Account $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
276 { "NSMSG_BAD_NICK", "Nickname $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
277 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
278 { "NSMSG_FAIL_RENAME", "Account $b%s$b not renamed to $b%s$b because it is in use by a network services, or contains invalid characters." },
279 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
280 { "NSMSG_SEARCH_MATCH", "Match: %s" },
281 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
282 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
283 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
284 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
285 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
286 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
287 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
288 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
289 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
290 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
291 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
292 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
293 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
294 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
295 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
296 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
297 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
298 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
299 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
300 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
301 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
302 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
303 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
304 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
305 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
306 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
307 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
308 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
309 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
310 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
311 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
312 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
313 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
314 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
316 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
317 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
319 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
320 { "NSEMAIL_ACTIVATION_BODY",
321 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
323 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
324 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
325 "This command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n"
326 "/msg %3$s@%4$s AUTH %5$s your-password\n"
327 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
328 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
330 "If you did NOT request this account, you do not need to do anything.\n"
331 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
332 { "NSEMAIL_ACTIVATION_BODY_WEB",
333 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
335 "To verify your email address and complete the account registration, visit the following URL:\n"
336 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
338 "If you did NOT request this account, you do not need to do anything.\n"
339 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
340 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
341 { "NSEMAIL_PASSWORD_CHANGE_BODY",
342 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
343 "To complete the password change, log on to %1$s and type the following command:\n"
344 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
345 "If you did NOT request your password to be changed, you do not need to do anything.\n"
346 "Please contact the %1$s staff if you have questions." },
347 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
348 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
349 "To complete the password change, click the following URL:\n"
350 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
351 "If you did NOT request your password to be changed, you do not need to do anything.\n"
352 "Please contact the %1$s staff if you have questions." },
353 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
354 #ifdef stupid_verify_old_email
355 { "NSEMAIL_EMAIL_CHANGE_BODY_NEW", "This email has been sent to verify that your email address belongs to the same person as account %5$s on %1$s. The SECOND HALF of your cookie is %2$.*6$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s ?????%2$.*6$s\n(Replace the ????? with the FIRST HALF of the cookie, as sent to your OLD email address.)\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
356 { "NSEMAIL_EMAIL_CHANGE_BODY_OLD", "This email has been sent to verify that you want to change your email for account %5$s on %1$s from this address to %7$s. The FIRST HALF of your cookie is %2$.*6$s\nTo verify your new address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$.*6$s?????\n(Replace the ????? with the SECOND HALF of the cookie, as sent to your NEW email address.)\nIf you did NOT request this change of email address, you do not need to do anything. Please contact the %1$s staff if you have questions." },
358 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
359 { "NSEMAIL_EMAIL_VERIFY_BODY", "This email has been sent to verify that this address belongs to the same person as %5$s on %1$s. Your cookie is %2$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
360 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
361 { "NSEMAIL_ALLOWAUTH_BODY", "This email has been sent to let you authenticate (auth) to account %5$s on %1$s. Your cookie is %2$s.\nTo auth to that account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this authorization, you do not need to do anything. Please contact the %1$s staff if you have questions." },
362 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
363 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
364 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
365 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
366 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
367 { "NSMSG_NOT_VALID_FAKEHOST_REGEX", "$b%s$b is not allowed by the admin, consult the valid vhost regex pattern in the config file under nickserv/valid_fakehost_regex." },
368 { "CHECKPASS_YES", "Yes." },
369 { "CHECKPASS_NO", "No." },
370 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
374 enum reclaim_action
{
380 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
381 static void nickserv_reclaim_p(void *data
);
384 unsigned int disable_nicks
: 1;
385 unsigned int valid_handle_regex_set
: 1;
386 unsigned int valid_nick_regex_set
: 1;
387 unsigned int valid_fakehost_regex_set
: 1;
388 unsigned int autogag_enabled
: 1;
389 unsigned int email_enabled
: 1;
390 unsigned int email_required
: 1;
391 unsigned int default_hostmask
: 1;
392 unsigned int warn_nick_owned
: 1;
393 unsigned int warn_clone_auth
: 1;
394 unsigned int sync_log
: 1;
395 unsigned long nicks_per_handle
;
396 unsigned long password_min_length
;
397 unsigned long password_min_digits
;
398 unsigned long password_min_upper
;
399 unsigned long password_min_lower
;
400 unsigned long db_backup_frequency
;
401 unsigned long handle_expire_frequency
;
402 unsigned long autogag_duration
;
403 unsigned long email_visible_level
;
404 unsigned long cookie_timeout
;
405 unsigned long handle_expire_delay
;
406 unsigned long nochan_handle_expire_delay
;
407 unsigned long modoper_level
;
408 unsigned long set_epithet_level
;
409 unsigned long set_title_level
;
410 unsigned long set_fakehost_level
;
411 unsigned long handles_per_email
;
412 unsigned long email_search_level
;
413 const char *network_name
;
414 const char *titlehost_suffix
;
415 regex_t valid_handle_regex
;
416 regex_t valid_nick_regex
;
417 regex_t valid_fakehost_regex
;
418 dict_t weak_password_dict
;
419 struct policer_params
*auth_policer_params
;
420 enum reclaim_action reclaim_action
;
421 enum reclaim_action auto_reclaim_action
;
422 unsigned long auto_reclaim_delay
;
423 unsigned char default_maxlogins
;
424 unsigned char hard_maxlogins
;
425 const char *auto_oper
;
426 const char *auto_admin
;
428 struct string_list
*denied_fakehost_words
;
431 /* We have 2^32 unique account IDs to use. */
432 unsigned long int highest_id
= 0;
435 canonicalize_hostmask(char *mask
)
437 char *out
= mask
, *temp
;
438 if ((temp
= strchr(mask
, '!'))) {
440 while (*temp
) *out
++ = *temp
++;
446 static struct handle_note
*
447 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
449 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
451 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
453 memcpy(note
->note
, text
, strlen(text
));
457 static struct handle_info
*
458 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
460 struct handle_info
*hi
;
462 hi
= calloc(1, sizeof(*hi
));
463 hi
->userlist_style
= HI_DEFAULT_STYLE
;
464 hi
->announcements
= '?';
465 hi
->handle
= strdup(handle
);
466 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
468 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
474 register_nick(const char *nick
, struct handle_info
*owner
)
476 struct nick_info
*ni
;
477 ni
= malloc(sizeof(struct nick_info
));
478 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
480 ni
->next
= owner
->nicks
;
482 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
486 delete_nick(struct nick_info
*ni
)
488 struct nick_info
*last
, *next
;
489 struct userNode
*user
;
490 /* Check to see if we should mark a user as unregistered. */
491 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
492 user
->modes
&= ~FLAGS_REGNICK
;
495 /* Remove ni from the nick_info linked list. */
496 if (ni
== ni
->owner
->nicks
) {
497 ni
->owner
->nicks
= ni
->next
;
499 last
= ni
->owner
->nicks
;
505 last
->next
= next
->next
;
507 dict_remove(nickserv_nick_dict
, ni
->nick
);
510 static unreg_func_t
*unreg_func_list
;
511 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
514 reg_unreg_func(unreg_func_t func
)
516 if (unreg_func_used
== unreg_func_size
) {
517 if (unreg_func_size
) {
518 unreg_func_size
<<= 1;
519 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
522 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
525 unreg_func_list
[unreg_func_used
++] = func
;
529 nickserv_free_cookie(void *data
)
531 struct handle_cookie
*cookie
= data
;
532 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
533 if (cookie
->data
) free(cookie
->data
);
538 free_handle_info(void *vhi
)
540 struct handle_info
*hi
= vhi
;
542 free_string_list(hi
->masks
);
543 free_string_list(hi
->ignores
);
547 delete_nick(hi
->nicks
);
553 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
554 nickserv_free_cookie(hi
->cookie
);
556 if (hi
->email_addr
) {
557 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
558 handle_info_list_remove(hil
, hi
);
560 dict_remove(nickserv_email_dict
, hi
->email_addr
);
565 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
568 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
571 struct userNode
*uNode
;
573 for (n
=0; n
<unreg_func_used
; n
++)
574 unreg_func_list
[n
](notify
, hi
);
576 if (nickserv_conf
.sync_log
) {
577 uNode
= GetUserH(hi
->users
->nick
);
581 set_user_handle_info(hi
->users
, NULL
, 0);
584 if (nickserv_conf
.disable_nicks
)
585 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
587 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
590 if (nickserv_conf
.sync_log
)
591 SyncLog("UNREGISTER %s", hi
->handle
);
593 dict_remove(nickserv_handle_dict
, hi
->handle
);
597 get_handle_info(const char *handle
)
599 return dict_find(nickserv_handle_dict
, handle
, 0);
603 get_nick_info(const char *nick
)
605 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
609 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
614 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
615 mn
= channel
->members
.list
[nn
];
616 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
623 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
624 if (!user
->handle_info
) {
626 send_message(user
, bot
, "MSG_AUTHENTICATE");
630 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
632 send_message(user
, bot
, "NSMSG_NO_ACCESS");
636 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
638 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
642 if (user
->handle_info
->opserv_level
< min_level
) {
644 send_message(user
, bot
, "NSMSG_NO_ACCESS");
652 is_valid_handle(const char *handle
)
654 struct userNode
*user
;
655 /* cant register a juped nick/service nick as handle, to prevent confusion */
656 user
= GetUserH(handle
);
657 if (user
&& IsLocal(user
))
659 /* check against maximum length */
660 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
662 /* for consistency, only allow account names that could be nicks */
663 if (!is_valid_nick(handle
))
665 /* disallow account names that look like bad words */
666 if (opserv_bad_channel(handle
))
668 /* test either regex or containing all valid chars */
669 if (nickserv_conf
.valid_handle_regex_set
) {
670 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
673 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
674 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
678 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
683 is_registerable_nick(const char *nick
)
685 /* make sure it could be used as an account name */
686 if (!is_valid_handle(nick
))
689 if (strlen(nick
) > NICKLEN
)
691 /* test either regex or as valid handle */
692 if (nickserv_conf
.valid_nick_regex_set
) {
693 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
696 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
697 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
703 /* this has been replaced with one in tools.c
706 is_valid_email_addr(const char *email)
708 return strchr(email, '@') != NULL;
714 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
716 if (hi
->email_addr
) {
717 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
718 return hi
->email_addr
;
728 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
730 struct handle_info
*hi
;
731 struct userNode
*target
;
735 if (!(hi
= get_handle_info(++name
))) {
736 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
741 if (!(target
= GetUserH(name
))) {
742 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
745 if (IsLocal(target
)) {
746 if (IsService(target
))
747 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
749 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
752 if (!(hi
= target
->handle_info
)) {
753 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
761 oper_outranks(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
) {
762 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
764 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
765 if ((user
->handle_info
->opserv_level
== 1000)
766 || (user
->handle_info
== hi
)
767 || ((user
->handle_info
->opserv_level
== 0)
768 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
769 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
773 reply("MSG_USER_OUTRANKED", hi
->handle
);
778 get_victim_oper(struct svccmd
*cmd
, struct userNode
*user
, const char *target
)
780 struct handle_info
*hi
;
781 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
783 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
784 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
787 return oper_outranks(cmd
, user
, hi
) ? hi
: NULL
;
791 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
795 /* If no hostmasks on the account, allow it. */
796 if (!hi
->masks
->used
)
798 /* If any hostmask matches, allow it. */
799 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
800 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
802 /* If they are allowauthed to this account, allow it (removing the aa). */
803 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
804 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
807 /* The user is not allowed to use this account. */
812 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
815 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
819 if (len
< nickserv_conf
.password_min_length
) {
821 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
824 if (!irccasecmp(pass
, handle
)) {
826 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
829 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
832 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
835 for (i
=0; i
<len
; i
++) {
836 if (isdigit(pass
[i
]))
838 if (isupper(pass
[i
]))
840 if (islower(pass
[i
]))
843 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
844 || (cnt_upper
< nickserv_conf
.password_min_upper
)
845 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
847 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
853 static auth_func_t
*auth_func_list
;
854 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
857 reg_auth_func(auth_func_t func
)
859 if (auth_func_used
== auth_func_size
) {
860 if (auth_func_size
) {
861 auth_func_size
<<= 1;
862 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
865 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
868 auth_func_list
[auth_func_used
++] = func
;
871 static handle_rename_func_t
*rf_list
;
872 static unsigned int rf_list_size
, rf_list_used
;
875 reg_handle_rename_func(handle_rename_func_t func
)
877 if (rf_list_used
== rf_list_size
) {
880 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
883 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
886 rf_list
[rf_list_used
++] = func
;
890 generate_fakehost(struct handle_info
*handle
)
892 struct userNode
*target
;
893 extern const char *hidden_host_suffix
;
894 static char buffer
[HOSTLEN
+1];
898 if (!handle
->fakehost
) {
899 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
904 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
905 else if (style
== 2) {
906 /* Due to the way fakehost is coded theres no way i can
907 get the exact user, so for now ill just take the first
909 for (target
= handle
->users
; target
; target
= target
->next_authed
)
912 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
915 } else if (handle
->fakehost
[0] == '.') {
916 /* A leading dot indicates the stored value is actually a title. */
917 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
920 return handle
->fakehost
;
924 apply_fakehost(struct handle_info
*handle
)
926 struct userNode
*target
;
931 fake
= generate_fakehost(handle
);
932 for (target
= handle
->users
; target
; target
= target
->next_authed
)
933 assign_fakehost(target
, fake
, 1);
936 void send_func_list(struct userNode
*user
)
939 struct handle_info
*old_info
;
941 old_info
= user
->handle_info
;
943 for (n
=0; n
<auth_func_used
; n
++)
944 auth_func_list
[n
](user
, old_info
);
948 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
951 struct handle_info
*old_info
;
953 /* This can happen if somebody uses COOKIE while authed, or if
954 * they re-auth to their current handle (which is silly, but users
956 if (user
->handle_info
== hi
)
959 if (user
->handle_info
) {
960 struct userNode
*other
;
963 userList_remove(&curr_helpers
, user
);
965 /* remove from next_authed linked list */
966 if (user
->handle_info
->users
== user
) {
967 user
->handle_info
->users
= user
->next_authed
;
969 for (other
= user
->handle_info
->users
;
970 other
->next_authed
!= user
;
971 other
= other
->next_authed
) ;
972 other
->next_authed
= user
->next_authed
;
974 /* if nobody left on old handle, and they're not an oper, remove !god */
975 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
976 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
977 /* record them as being last seen at this time */
978 user
->handle_info
->lastseen
= now
;
979 /* and record their hostmask */
980 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
982 old_info
= user
->handle_info
;
983 user
->handle_info
= hi
;
984 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
985 HANDLE_CLEAR_FLAG(hi
, HELPING
);
987 /* Call auth handlers */
988 if (!GetUserH(user
->nick
))
992 struct nick_info
*ni
;
994 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
995 if (nickserv_conf
.warn_clone_auth
) {
996 struct userNode
*other
;
997 for (other
= hi
->users
; other
; other
= other
->next_authed
)
998 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1001 /* Add this auth to users list of current auths */
1002 user
->next_authed
= hi
->users
;
1005 /* Add to helpers list */
1007 userList_append(&curr_helpers
, user
);
1009 /* Set the fakehost */
1010 if (hi
->fakehost
|| old_info
)
1014 #ifdef WITH_PROTOCOL_P10
1015 /* Stamp users with their account name. */
1016 char *id
= hi
->handle
;
1018 const char *id
= "???";
1020 /* Mark all the nicks registered to this
1021 * account as registered nicks
1022 * - Why not just this one? -rubin */
1023 if (!nickserv_conf
.disable_nicks
) {
1024 struct nick_info
*ni
;
1025 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1026 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1027 user
->modes
|= FLAGS_REGNICK
;
1032 /* send the account to the ircd */
1033 StampUser(user
, id
, hi
->registered
);
1036 /* Stop trying to kick this user off their nick */
1037 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1038 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1040 /* We cannot clear the user's account ID, unfortunately. */
1041 user
->next_authed
= NULL
;
1044 /* Call auth handlers */
1045 if (GetUserH(user
->nick
)) {
1046 for (n
=0; n
<auth_func_used
; n
++)
1047 auth_func_list
[n
](user
, old_info
);
1051 static struct handle_info
*
1052 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1054 struct handle_info
*hi
;
1055 struct nick_info
*ni
;
1056 char crypted
[MD5_CRYPT_LENGTH
];
1058 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1059 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1063 if(strlen(handle
) > 15)
1065 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1069 if (!is_secure_password(handle
, passwd
, user
))
1072 cryptpass(passwd
, crypted
);
1073 hi
= register_handle(handle
, crypted
, 0);
1074 hi
->masks
= alloc_string_list(1);
1075 hi
->ignores
= alloc_string_list(1);
1077 hi
->language
= lang_C
;
1078 hi
->registered
= now
;
1080 hi
->flags
= HI_DEFAULT_FLAGS
;
1081 if (settee
&& !no_auth
)
1082 set_user_handle_info(settee
, hi
, 1);
1085 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1086 else if (nickserv_conf
.disable_nicks
)
1087 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1088 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1089 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1091 register_nick(user
->nick
, hi
);
1092 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1094 if (settee
&& (user
!= settee
))
1095 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1100 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1102 cookie
->hi
->cookie
= cookie
;
1103 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1106 /* Contributed by the great sneep of afternet ;) */
1107 /* Since this gets used in a URL, we want to avoid stuff that confuses
1108 * email clients such as ] and ?. a-z, 0-9 only.
1110 void genpass(char *str
, int len
)
1115 for(i
= 0; i
< len
; i
++)
1119 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1120 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1128 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1130 struct handle_cookie
*cookie
;
1131 char subject
[128], body
[4096], *misc
;
1132 const char *netname
, *fmt
;
1136 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1140 cookie
= calloc(1, sizeof(*cookie
));
1142 cookie
->type
= type
;
1143 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1145 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1146 /* Adding dedicated password gen function for more control -Rubin */
1147 genpass(cookie
->cookie
, 10);
1149 *inttobase64(cookie->cookie, rand(), 5);
1150 *inttobase64(cookie->cookie+5, rand(), 5);
1153 netname
= nickserv_conf
.network_name
;
1156 switch (cookie
->type
) {
1158 hi
->passwd
[0] = 0; /* invalidate password */
1159 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1160 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1161 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1164 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1166 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1168 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1171 case PASSWORD_CHANGE
:
1172 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1173 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1174 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1176 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1178 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1179 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1182 misc
= hi
->email_addr
;
1183 hi
->email_addr
= cookie
->data
;
1184 #ifdef stupid_verify_old_email
1186 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1187 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1188 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1189 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1190 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1191 sendmail(nickserv
, hi
, subject
, body
, 1);
1192 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1193 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1196 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1197 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1198 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1199 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1200 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1201 sendmail(nickserv
, hi
, subject
, body
, 1);
1203 #ifdef stupid_verify_old_email
1206 hi
->email_addr
= misc
;
1209 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1210 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1211 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1212 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1213 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1216 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1220 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1221 nickserv_bake_cookie(cookie
);
1225 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1227 cookie
->hi
->cookie
= NULL
;
1228 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1229 nickserv_free_cookie(cookie
);
1233 nickserv_free_email_addr(void *data
)
1235 handle_info_list_clean(data
);
1240 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1242 struct handle_info_list
*hil
;
1243 /* Remove from old handle_info_list ... */
1244 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1245 handle_info_list_remove(hil
, hi
);
1246 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1247 hi
->email_addr
= NULL
;
1249 /* Add to the new list.. */
1250 if (new_email_addr
) {
1251 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1252 hil
= calloc(1, sizeof(*hil
));
1253 hil
->tag
= strdup(new_email_addr
);
1254 handle_info_list_init(hil
);
1255 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1257 handle_info_list_append(hil
, hi
);
1258 hi
->email_addr
= hil
->tag
;
1262 static NICKSERV_FUNC(cmd_register
)
1265 struct handle_info
*hi
;
1266 const char *email_addr
, *password
;
1267 char syncpass
[MD5_CRYPT_LENGTH
];
1268 int no_auth
, weblink
;
1270 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1271 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1275 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1276 /* Require the first handle registered to belong to someone +o. */
1277 reply("NSMSG_REQUIRE_OPER");
1281 if (user
->handle_info
) {
1282 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1286 if (IsRegistering(user
)) {
1287 reply("NSMSG_ALREADY_REGISTERING");
1291 if (IsStamped(user
)) {
1292 /* Unauthenticated users might still have been stamped
1293 previously and could therefore have a hidden host;
1294 do not allow them to register a new account. */
1295 reply("NSMSG_STAMPED_REGISTER");
1299 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1301 if (!is_valid_handle(argv
[1])) {
1302 reply("NSMSG_BAD_HANDLE", argv
[1]);
1307 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1308 struct handle_info_list
*hil
;
1311 /* Remember email address. */
1312 email_addr
= argv
[3];
1314 /* Check that the email address looks valid.. */
1315 if (!valid_email(email_addr
)) {
1316 reply("NSMSG_BAD_EMAIL_ADDR");
1320 /* .. and that we are allowed to send to it. */
1321 if ((str
= sendmail_prohibited_address(email_addr
))) {
1322 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1326 /* If we do email verify, make sure we don't spam the address. */
1327 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1329 for (nn
=0; nn
<hil
->used
; nn
++) {
1330 if (hil
->list
[nn
]->cookie
) {
1331 reply("NSMSG_EMAIL_UNACTIVATED");
1335 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1336 reply("NSMSG_EMAIL_OVERUSED");
1349 /* Webregister hack - send URL instead of IRC cookie
1352 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1356 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1358 /* Add any masks they should get. */
1359 if (nickserv_conf
.default_hostmask
) {
1360 string_list_append(hi
->masks
, strdup("*@*"));
1362 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1363 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1364 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1367 /* If they're the first to register, give them level 1000. */
1368 if (dict_size(nickserv_handle_dict
) == 1) {
1369 hi
->opserv_level
= 1000;
1370 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1373 /* Set their email address. */
1375 nickserv_set_email_addr(hi
, email_addr
);
1377 /* If they need to do email verification, tell them. */
1379 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1381 /* Set registering flag.. */
1382 user
->modes
|= FLAGS_REGISTERING
;
1384 if (nickserv_conf
.sync_log
) {
1385 cryptpass(password
, syncpass
);
1387 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1388 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1391 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1394 /* this wont work if email is required .. */
1395 process_adduser_pending(user
);
1400 static NICKSERV_FUNC(cmd_oregister
)
1402 struct userNode
*settee
= NULL
;
1403 struct handle_info
*hi
;
1404 char* account
= NULL
;
1410 NICKSERV_MIN_PARMS(3);
1414 if (nickserv_conf
.email_required
) {
1415 NICKSERV_MIN_PARMS(4);
1417 if (argc
>= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1418 if (strchr(argv
[4], '@') || argc
>= 6) /* If @, its mask not nick */
1428 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1429 if (strchr(argv
[3], '@') || argc
>= 5) /* If @, its mask not nick */
1438 /* If they passed a nick, look for that user.. */
1439 if (nick
&& !(settee
= GetUserH(nick
))) {
1440 reply("MSG_NICK_UNKNOWN", argv
[4]);
1443 /* If the setee is already authed, we cant add a 2nd account for them.. */
1444 if (settee
&& settee
->handle_info
) {
1445 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1448 /* If there is no default mask in the conf, and they didn't pass a mask,
1449 * but we did find a user by nick, generate the mask */
1451 if (nickserv_conf
.default_hostmask
)
1454 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1456 reply("NSMSG_REGISTER_BAD_NICKMASK");
1461 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1462 return 0; /* error reply handled by above */
1465 nickserv_set_email_addr(hi
, email
);
1468 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1469 string_list_append(hi
->masks
, mask_canonicalized
);
1472 if (nickserv_conf
.sync_log
)
1473 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1478 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1481 struct userNode
*target
;
1482 char *new_mask
= strdup(pretty_mask(mask
));
1483 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1484 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1485 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1490 string_list_append(hi
->ignores
, new_mask
);
1491 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1493 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1494 irc_silence(target
, new_mask
, 1);
1499 static NICKSERV_FUNC(cmd_addignore
)
1501 NICKSERV_MIN_PARMS(2);
1503 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1506 static NICKSERV_FUNC(cmd_oaddignore
)
1508 struct handle_info
*hi
;
1510 NICKSERV_MIN_PARMS(3);
1511 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1514 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1518 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1521 struct userNode
*target
;
1522 char *pmask
= strdup(pretty_mask(del_mask
));
1523 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1524 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1525 char *old_mask
= hi
->ignores
->list
[i
];
1526 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1527 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1528 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1529 irc_silence(target
, old_mask
, 0);
1536 reply("NSMSG_DELMASK_NOT_FOUND");
1540 static NICKSERV_FUNC(cmd_delignore
)
1542 NICKSERV_MIN_PARMS(2);
1543 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1546 static NICKSERV_FUNC(cmd_odelignore
)
1548 struct handle_info
*hi
;
1549 NICKSERV_MIN_PARMS(3);
1550 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1552 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1555 static NICKSERV_FUNC(cmd_handleinfo
)
1558 unsigned int i
, pos
=0, herelen
;
1559 struct userNode
*target
, *next_un
;
1560 struct handle_info
*hi
;
1561 const char *nsmsg_none
;
1564 if (!(hi
= user
->handle_info
)) {
1565 reply("NSMSG_MUST_AUTH");
1568 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1572 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1573 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1575 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1578 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1579 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1581 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1584 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1585 if (HANDLE_FLAGGED(hi
, FROZEN
))
1586 reply("NSMSG_HANDLEINFO_VACATION");
1588 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1589 struct do_not_register
*dnr
;
1590 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1591 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1592 if (!oper_outranks(cmd
, user
, hi
))
1594 } else if (hi
!= user
->handle_info
) {
1595 reply("NSMSG_HANDLEINFO_END");
1599 if (nickserv_conf
.email_enabled
)
1600 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1604 switch (hi
->cookie
->type
) {
1605 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1606 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1607 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1608 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1609 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1615 unsigned long flen
= 1;
1616 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1618 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1619 if (hi
->flags
& 1 << i
)
1620 flags
[flen
++] = handle_flags
[i
];
1622 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1624 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1627 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1628 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1629 || (hi
->opserv_level
> 0)) {
1630 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1633 if (IsHelping(user
) || IsOper(user
))
1638 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1639 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1644 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1646 if (hi
->last_quit_host
[0])
1647 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1649 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1651 if (nickserv_conf
.disable_nicks
) {
1652 /* nicks disabled; don't show anything about registered nicks */
1653 } else if (hi
->nicks
) {
1654 struct nick_info
*ni
, *next_ni
;
1655 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1656 herelen
= strlen(ni
->nick
);
1657 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1659 goto print_nicks_buff
;
1663 memcpy(buff
+pos
, ni
->nick
, herelen
);
1664 pos
+= herelen
; buff
[pos
++] = ' ';
1668 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1673 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1676 if (hi
->masks
->used
) {
1677 for (i
=0; i
< hi
->masks
->used
; i
++) {
1678 herelen
= strlen(hi
->masks
->list
[i
]);
1679 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1681 goto print_mask_buff
;
1683 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1684 pos
+= herelen
; buff
[pos
++] = ' ';
1685 if (i
+1 == hi
->masks
->used
) {
1688 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1693 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1696 if (hi
->ignores
->used
) {
1697 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1698 herelen
= strlen(hi
->ignores
->list
[i
]);
1699 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1701 goto print_ignore_buff
;
1703 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1704 pos
+= herelen
; buff
[pos
++] = ' ';
1705 if (i
+1 == hi
->ignores
->used
) {
1708 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1713 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1717 struct userData
*channel
, *next
;
1720 for (channel
= hi
->channels
; channel
; channel
= next
) {
1721 next
= channel
->u_next
;
1722 name
= channel
->channel
->channel
->name
;
1723 herelen
= strlen(name
);
1724 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1726 goto print_chans_buff
;
1728 if (IsUserSuspended(channel
))
1730 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1734 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1739 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1742 for (target
= hi
->users
; target
; target
= next_un
) {
1743 herelen
= strlen(target
->nick
);
1744 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1746 goto print_cnick_buff
;
1748 next_un
= target
->next_authed
;
1750 memcpy(buff
+pos
, target
->nick
, herelen
);
1751 pos
+= herelen
; buff
[pos
++] = ' ';
1755 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1760 reply("NSMSG_HANDLEINFO_END");
1764 static NICKSERV_FUNC(cmd_userinfo
)
1766 struct userNode
*target
;
1768 NICKSERV_MIN_PARMS(2);
1769 if (!(target
= GetUserH(argv
[1]))) {
1770 reply("MSG_NICK_UNKNOWN", argv
[1]);
1773 if (target
->handle_info
)
1774 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1776 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1780 static NICKSERV_FUNC(cmd_nickinfo
)
1782 struct nick_info
*ni
;
1784 NICKSERV_MIN_PARMS(2);
1785 if (!(ni
= get_nick_info(argv
[1]))) {
1786 reply("MSG_NICK_UNKNOWN", argv
[1]);
1789 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1793 static NICKSERV_FUNC(cmd_rename_handle
)
1795 struct handle_info
*hi
;
1796 struct userNode
*uNode
;
1800 NICKSERV_MIN_PARMS(3);
1801 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1803 if (!is_valid_handle(argv
[2])) {
1804 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1807 if (get_handle_info(argv
[2])) {
1808 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1811 if(strlen(argv
[2]) > 15)
1813 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1817 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1818 hi
->handle
= strdup(argv
[2]);
1819 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1820 for (nn
=0; nn
<rf_list_used
; nn
++)
1821 rf_list
[nn
](hi
, old_handle
);
1823 if (nickserv_conf
.sync_log
) {
1824 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1825 irc_rename(uNode
, hi
->handle
);
1827 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1830 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1831 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1832 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1838 static failpw_func_t
*failpw_func_list
;
1839 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1842 reg_failpw_func(failpw_func_t func
)
1844 if (failpw_func_used
== failpw_func_size
) {
1845 if (failpw_func_size
) {
1846 failpw_func_size
<<= 1;
1847 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1849 failpw_func_size
= 8;
1850 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1853 failpw_func_list
[failpw_func_used
++] = func
;
1857 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1859 * called by nefariouses enhanced AC login-on-connect code
1862 struct handle_info
*loc_auth(char *handle
, char *password
)
1864 int pw_arg
, used
, maxlogins
;
1867 struct handle_info
*hi
;
1868 struct userNode
*other
;
1870 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1876 /* We don't know the users hostname, or anything because they
1877 * havn't registered yet. So we can only allow LOC if your
1878 * account has *@* as a hostmask.
1880 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1882 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1891 /* Responses from here on look up the language used by the handle they asked about. */
1892 if (!checkpass(password
, hi
->passwd
)) {
1895 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1898 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1899 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1900 if (++used
>= maxlogins
) {
1907 static NICKSERV_FUNC(cmd_auth
)
1909 int pw_arg
, used
, maxlogins
;
1910 struct handle_info
*hi
;
1912 struct userNode
*other
;
1914 if (user
->handle_info
) {
1915 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1918 if (IsStamped(user
)) {
1919 /* Unauthenticated users might still have been stamped
1920 previously and could therefore have a hidden host;
1921 do not allow them to authenticate. */
1922 reply("NSMSG_STAMPED_AUTH");
1926 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1928 } else if (argc
== 2) {
1929 if (nickserv_conf
.disable_nicks
) {
1930 if (!(hi
= get_handle_info(user
->nick
))) {
1931 reply("NSMSG_HANDLE_NOT_FOUND");
1935 /* try to look up their handle from their nick */
1936 struct nick_info
*ni
;
1937 ni
= get_nick_info(user
->nick
);
1939 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1946 reply("MSG_MISSING_PARAMS", argv
[0]);
1947 svccmd_send_help_brief(user
, nickserv
, cmd
);
1951 reply("NSMSG_HANDLE_NOT_FOUND");
1954 /* Responses from here on look up the language used by the handle they asked about. */
1955 passwd
= argv
[pw_arg
];
1956 if (!valid_user_for(user
, hi
)) {
1957 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1958 send_message_type(4, user
, cmd
->parent
->bot
,
1959 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1962 send_message_type(4, user
, cmd
->parent
->bot
,
1963 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1965 argv
[pw_arg
] = "BADMASK";
1968 if (!checkpass(passwd
, hi
->passwd
)) {
1970 send_message_type(4, user
, cmd
->parent
->bot
,
1971 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1972 argv
[pw_arg
] = "BADPASS";
1973 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1974 if (nickserv_conf
.autogag_enabled
) {
1975 if (!user
->auth_policer
.params
) {
1976 user
->auth_policer
.last_req
= now
;
1977 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1979 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1981 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1982 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1983 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1985 argv
[pw_arg
] = "GAGGED";
1990 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1991 send_message_type(4, user
, cmd
->parent
->bot
,
1992 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1993 argv
[pw_arg
] = "SUSPENDED";
1996 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1997 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1998 if (++used
>= maxlogins
) {
1999 send_message_type(4, user
, cmd
->parent
->bot
,
2000 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2002 argv
[pw_arg
] = "MAXLOGINS";
2007 set_user_handle_info(user
, hi
, 1);
2008 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2009 reply("NSMSG_PLEASE_SET_EMAIL");
2010 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2011 reply("NSMSG_WEAK_PASSWORD");
2012 if (hi
->passwd
[0] != '$')
2013 cryptpass(passwd
, hi
->passwd
);
2015 /* If a channel was waiting for this user to auth,
2016 * finish adding them */
2017 process_adduser_pending(user
);
2019 reply("NSMSG_AUTH_SUCCESS");
2022 /* Set +x if autohide is on */
2023 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2024 irc_umode(user
, "+x");
2026 if(!IsOper(user
)) /* If they arnt already opered.. */
2028 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2029 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2031 irc_umode(user
,nickserv_conf
.auto_admin
);
2032 reply("NSMSG_AUTO_OPER_ADMIN");
2034 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2036 irc_umode(user
,nickserv_conf
.auto_oper
);
2037 reply("NSMSG_AUTO_OPER");
2041 /* Wipe out the pass for the logs */
2042 argv
[pw_arg
] = "****";
2046 static allowauth_func_t
*allowauth_func_list
;
2047 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2050 reg_allowauth_func(allowauth_func_t func
)
2052 if (allowauth_func_used
== allowauth_func_size
) {
2053 if (allowauth_func_size
) {
2054 allowauth_func_size
<<= 1;
2055 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2057 allowauth_func_size
= 8;
2058 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2061 allowauth_func_list
[allowauth_func_used
++] = func
;
2064 static NICKSERV_FUNC(cmd_allowauth
)
2066 struct userNode
*target
;
2067 struct handle_info
*hi
;
2070 NICKSERV_MIN_PARMS(2);
2071 if (!(target
= GetUserH(argv
[1]))) {
2072 reply("MSG_NICK_UNKNOWN", argv
[1]);
2075 if (target
->handle_info
) {
2076 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2079 if (IsStamped(target
)) {
2080 /* Unauthenticated users might still have been stamped
2081 previously and could therefore have a hidden host;
2082 do not allow them to authenticate to an account. */
2083 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2088 else if (!(hi
= get_handle_info(argv
[2]))) {
2089 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2093 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2094 reply("MSG_USER_OUTRANKED", hi
->handle
);
2097 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2098 || (hi
->opserv_level
> 0))
2099 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2100 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2103 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2104 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2105 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2106 if (nickserv_conf
.email_enabled
)
2107 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2109 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2110 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2112 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2114 for (n
=0; n
<allowauth_func_used
; n
++)
2115 allowauth_func_list
[n
](user
, target
, hi
);
2119 static NICKSERV_FUNC(cmd_authcookie
)
2121 struct handle_info
*hi
;
2123 NICKSERV_MIN_PARMS(2);
2124 if (user
->handle_info
) {
2125 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2128 if (IsStamped(user
)) {
2129 /* Unauthenticated users might still have been stamped
2130 previously and could therefore have a hidden host;
2131 do not allow them to authenticate to an account. */
2132 reply("NSMSG_STAMPED_AUTHCOOKIE");
2135 if (!(hi
= get_handle_info(argv
[1]))) {
2136 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2139 if (!hi
->email_addr
) {
2140 reply("MSG_SET_EMAIL_ADDR");
2143 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2147 static NICKSERV_FUNC(cmd_delcookie
)
2149 struct handle_info
*hi
;
2151 hi
= user
->handle_info
;
2153 reply("NSMSG_NO_COOKIE");
2156 switch (hi
->cookie
->type
) {
2159 reply("NSMSG_MUST_TIME_OUT");
2162 nickserv_eat_cookie(hi
->cookie
);
2163 reply("NSMSG_ATE_COOKIE");
2169 static NICKSERV_FUNC(cmd_odelcookie
)
2171 struct handle_info
*hi
;
2173 NICKSERV_MIN_PARMS(2);
2175 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2179 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2183 switch (hi
->cookie
->type
) {
2185 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2186 if (nickserv_conf
.sync_log
)
2187 SyncLog("ACCOUNTACC %s", hi
->handle
);
2189 case PASSWORD_CHANGE
:
2190 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2191 if (nickserv_conf
.sync_log
)
2192 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2195 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2196 if (nickserv_conf
.sync_log
)
2197 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2199 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2200 if (nickserv_conf
.sync_log
)
2201 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2204 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2205 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2209 nickserv_eat_cookie(hi
->cookie
);
2210 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2215 static NICKSERV_FUNC(cmd_resetpass
)
2217 struct handle_info
*hi
;
2218 char crypted
[MD5_CRYPT_LENGTH
];
2221 NICKSERV_MIN_PARMS(3);
2222 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2226 if (user
->handle_info
) {
2227 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2230 if (IsStamped(user
)) {
2231 /* Unauthenticated users might still have been stamped
2232 previously and could therefore have a hidden host;
2233 do not allow them to activate an account. */
2234 reply("NSMSG_STAMPED_RESETPASS");
2237 if (!(hi
= get_handle_info(argv
[1]))) {
2238 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2241 if (!hi
->email_addr
) {
2242 reply("MSG_SET_EMAIL_ADDR");
2245 cryptpass(argv
[2], crypted
);
2247 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2251 static NICKSERV_FUNC(cmd_cookie
)
2253 struct handle_info
*hi
;
2256 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2259 NICKSERV_MIN_PARMS(3);
2260 if (!(hi
= get_handle_info(argv
[1]))) {
2261 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2267 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2268 reply("NSMSG_HANDLE_SUSPENDED");
2273 reply("NSMSG_NO_COOKIE");
2277 /* Check validity of operation before comparing cookie to
2278 * prohibit guessing by authed users. */
2279 if (user
->handle_info
2280 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2281 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2282 reply("NSMSG_CANNOT_COOKIE");
2286 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2287 reply("NSMSG_BAD_COOKIE");
2291 switch (hi
->cookie
->type
) {
2293 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2294 set_user_handle_info(user
, hi
, 1);
2295 reply("NSMSG_HANDLE_ACTIVATED");
2296 if (nickserv_conf
.sync_log
)
2297 SyncLog("ACCOUNTACC %s", hi
->handle
);
2299 case PASSWORD_CHANGE
:
2300 set_user_handle_info(user
, hi
, 1);
2301 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2302 reply("NSMSG_PASSWORD_CHANGED");
2303 if (nickserv_conf
.sync_log
)
2304 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2307 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2309 * This should only happen if an OREGISTER was sent. Require
2310 * email must be enabled! - SiRVulcaN
2312 if (nickserv_conf
.sync_log
)
2313 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2315 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2316 reply("NSMSG_EMAIL_CHANGED");
2317 if (nickserv_conf
.sync_log
)
2318 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2321 set_user_handle_info(user
, hi
, 1);
2322 reply("NSMSG_AUTH_SUCCESS");
2325 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2326 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2330 nickserv_eat_cookie(hi
->cookie
);
2332 process_adduser_pending(user
);
2337 static NICKSERV_FUNC(cmd_oregnick
) {
2339 struct handle_info
*target
;
2340 struct nick_info
*ni
;
2342 NICKSERV_MIN_PARMS(3);
2343 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2346 if (!is_registerable_nick(nick
)) {
2347 reply("NSMSG_BAD_NICK", nick
);
2350 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2352 reply("NSMSG_NICK_EXISTS", nick
);
2355 register_nick(nick
, target
);
2356 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2360 static NICKSERV_FUNC(cmd_regnick
) {
2362 struct nick_info
*ni
;
2364 if (!is_registerable_nick(user
->nick
)) {
2365 reply("NSMSG_BAD_NICK", user
->nick
);
2368 /* count their nicks, see if it's too many */
2369 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2370 if (n
>= nickserv_conf
.nicks_per_handle
) {
2371 reply("NSMSG_TOO_MANY_NICKS");
2374 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2376 reply("NSMSG_NICK_EXISTS", user
->nick
);
2379 register_nick(user
->nick
, user
->handle_info
);
2380 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2384 static NICKSERV_FUNC(cmd_pass
)
2386 struct handle_info
*hi
;
2387 const char *old_pass
, *new_pass
;
2389 NICKSERV_MIN_PARMS(3);
2390 hi
= user
->handle_info
;
2394 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2395 if (!checkpass(old_pass
, hi
->passwd
)) {
2396 argv
[1] = "BADPASS";
2397 reply("NSMSG_PASSWORD_INVALID");
2400 cryptpass(new_pass
, hi
->passwd
);
2401 if (nickserv_conf
.sync_log
)
2402 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2404 reply("NSMSG_PASS_SUCCESS");
2409 nickserv_addmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2412 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2413 for (i
=0; i
<hi
->masks
->used
; i
++) {
2414 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2415 reply("NSMSG_ADDMASK_ALREADY", new_mask
);
2420 string_list_append(hi
->masks
, new_mask
);
2421 reply("NSMSG_ADDMASK_SUCCESS", new_mask
);
2425 static NICKSERV_FUNC(cmd_addmask
)
2428 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2429 int res
= nickserv_addmask(cmd
, user
, user
->handle_info
, mask
);
2433 if (!is_gline(argv
[1])) {
2434 reply("NSMSG_MASK_INVALID", argv
[1]);
2437 return nickserv_addmask(cmd
, user
, user
->handle_info
, argv
[1]);
2441 static NICKSERV_FUNC(cmd_oaddmask
)
2443 struct handle_info
*hi
;
2445 NICKSERV_MIN_PARMS(3);
2446 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2448 return nickserv_addmask(cmd
, user
, hi
, argv
[2]);
2452 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2455 for (i
=0; i
<hi
->masks
->used
; i
++) {
2456 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2457 char *old_mask
= hi
->masks
->list
[i
];
2458 if (hi
->masks
->used
== 1) {
2459 reply("NSMSG_DELMASK_NOTLAST");
2462 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2463 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2468 reply("NSMSG_DELMASK_NOT_FOUND");
2472 static NICKSERV_FUNC(cmd_delmask
)
2474 NICKSERV_MIN_PARMS(2);
2475 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1]);
2478 static NICKSERV_FUNC(cmd_odelmask
)
2480 struct handle_info
*hi
;
2481 NICKSERV_MIN_PARMS(3);
2482 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2484 return nickserv_delmask(cmd
, user
, hi
, argv
[2]);
2488 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2489 unsigned int nn
, add
= 1, pos
;
2490 unsigned long added
, removed
, flag
;
2492 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2494 case '+': add
= 1; break;
2495 case '-': add
= 0; break;
2497 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2498 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2501 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2502 /* cheesy avoidance of looking up the flag name.. */
2503 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2506 flag
= 1 << (pos
- 1);
2508 added
|= flag
, removed
&= ~flag
;
2510 removed
|= flag
, added
&= ~flag
;
2515 *premoved
= removed
;
2520 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2522 unsigned long before
, after
, added
, removed
;
2523 struct userNode
*uNode
;
2525 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2526 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2528 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2529 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2531 /* Strip helping flag if they're only a support helper and not
2532 * currently in #support. */
2533 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2534 struct channelList
*schannels
;
2536 schannels
= chanserv_support_channels();
2537 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2538 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2539 if (GetUserMode(schannels
->list
[ii
], uNode
))
2541 if (ii
< schannels
->used
)
2545 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2548 if (after
&& !before
) {
2549 /* Add user to current helper list. */
2550 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2551 userList_append(&curr_helpers
, uNode
);
2552 } else if (!after
&& before
) {
2553 /* Remove user from current helper list. */
2554 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2555 userList_remove(&curr_helpers
, uNode
);
2562 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2566 char *set_display
[] = {
2567 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2568 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2569 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2572 reply("NSMSG_SETTING_LIST");
2573 reply("NSMSG_SETTING_LIST_HEADER");
2575 /* Do this so options are presented in a consistent order. */
2576 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2577 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2578 opt(cmd
, user
, hi
, override
, 0, NULL
);
2579 reply("NSMSG_SETTING_LIST_END");
2582 static NICKSERV_FUNC(cmd_set
)
2584 struct handle_info
*hi
;
2587 hi
= user
->handle_info
;
2589 set_list(cmd
, user
, hi
, 0);
2592 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2593 reply("NSMSG_INVALID_OPTION", argv
[1]);
2596 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2599 static NICKSERV_FUNC(cmd_oset
)
2601 struct handle_info
*hi
;
2604 NICKSERV_MIN_PARMS(2);
2606 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2610 set_list(cmd
, user
, hi
, 0);
2614 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2615 reply("NSMSG_INVALID_OPTION", argv
[2]);
2619 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
2622 static OPTION_FUNC(opt_info
)
2626 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2628 hi
->infoline
= NULL
;
2630 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2634 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2635 reply("NSMSG_SET_INFO", info
);
2639 static OPTION_FUNC(opt_width
)
2642 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2644 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2645 hi
->screen_width
= MIN_LINE_SIZE
;
2646 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2647 hi
->screen_width
= MAX_LINE_SIZE
;
2649 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
2653 static OPTION_FUNC(opt_tablewidth
)
2656 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2658 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2659 hi
->table_width
= MIN_LINE_SIZE
;
2660 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2661 hi
->table_width
= MAX_LINE_SIZE
;
2663 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2667 static OPTION_FUNC(opt_color
)
2670 if (enabled_string(argv
[1]))
2671 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2672 else if (disabled_string(argv
[1]))
2673 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2675 reply("MSG_INVALID_BINARY", argv
[1]);
2680 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2684 static OPTION_FUNC(opt_privmsg
)
2687 if (enabled_string(argv
[1]))
2688 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2689 else if (disabled_string(argv
[1]))
2690 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2692 reply("MSG_INVALID_BINARY", argv
[1]);
2697 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2701 static OPTION_FUNC(opt_autohide
)
2704 if (enabled_string(argv
[1]))
2705 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2706 else if (disabled_string(argv
[1]))
2707 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2709 reply("MSG_INVALID_BINARY", argv
[1]);
2714 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2718 static OPTION_FUNC(opt_style
)
2723 if (!irccasecmp(argv
[1], "Clean"))
2724 hi
->userlist_style
= HI_STYLE_CLEAN
;
2725 else if (!irccasecmp(argv
[1], "Advanced"))
2726 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2727 else if (!irccasecmp(argv
[1], "Classic"))
2728 hi
->userlist_style
= HI_STYLE_CLASSIC
;
2729 else /* Default to normal */
2730 hi
->userlist_style
= HI_STYLE_NORMAL
;
2731 } /* TODO: give error if unknow style is chosen */
2733 switch (hi
->userlist_style
) {
2734 case HI_STYLE_ADVANCED
:
2737 case HI_STYLE_CLASSIC
:
2740 case HI_STYLE_CLEAN
:
2743 case HI_STYLE_NORMAL
:
2748 reply("NSMSG_SET_STYLE", style
);
2752 static OPTION_FUNC(opt_announcements
)
2757 if (enabled_string(argv
[1]))
2758 hi
->announcements
= 'y';
2759 else if (disabled_string(argv
[1]))
2760 hi
->announcements
= 'n';
2761 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2762 hi
->announcements
= '?';
2764 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
2769 switch (hi
->announcements
) {
2770 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2771 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2772 case '?': choice
= "default"; break;
2773 default: choice
= "unknown"; break;
2775 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
2779 static OPTION_FUNC(opt_password
)
2782 reply("NSMSG_USE_CMD_PASS");
2787 cryptpass(argv
[1], hi
->passwd
);
2789 if (nickserv_conf
.sync_log
)
2790 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2792 reply("NSMSG_SET_PASSWORD", "***");
2796 static OPTION_FUNC(opt_flags
)
2799 unsigned int ii
, flen
;
2802 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2807 nickserv_apply_flags(user
, hi
, argv
[1]);
2809 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2810 if (hi
->flags
& (1 << ii
))
2811 flags
[flen
++] = handle_flags
[ii
];
2814 reply("NSMSG_SET_FLAGS", flags
);
2816 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2820 static OPTION_FUNC(opt_email
)
2824 if (!valid_email(argv
[1])) {
2825 reply("NSMSG_BAD_EMAIL_ADDR");
2828 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2829 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2832 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2833 reply("NSMSG_EMAIL_SAME");
2835 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2837 nickserv_set_email_addr(hi
, argv
[1]);
2839 nickserv_eat_cookie(hi
->cookie
);
2840 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2843 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2847 static OPTION_FUNC(opt_maxlogins
)
2849 unsigned char maxlogins
;
2851 maxlogins
= strtoul(argv
[1], NULL
, 0);
2852 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2853 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2856 hi
->maxlogins
= maxlogins
;
2858 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2859 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
2863 static OPTION_FUNC(opt_advanced
)
2866 if (enabled_string(argv
[1]))
2867 HANDLE_SET_FLAG(hi
, ADVANCED
);
2868 else if (disabled_string(argv
[1]))
2869 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
2871 reply("MSG_INVALID_BINARY", argv
[1]);
2876 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
2880 static OPTION_FUNC(opt_language
)
2882 struct language
*lang
;
2884 lang
= language_find(argv
[1]);
2885 if (irccasecmp(lang
->name
, argv
[1]))
2886 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2887 hi
->language
= lang
;
2889 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
2894 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2895 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2897 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2898 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2899 && (user
->handle_info
->opserv_level
< 1000))) {
2900 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2903 if ((user
->handle_info
->opserv_level
< new_level
)
2904 || ((user
->handle_info
->opserv_level
== new_level
)
2905 && (user
->handle_info
->opserv_level
< 1000))) {
2906 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2909 if (user
->handle_info
== target
) {
2910 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2913 if (target
->opserv_level
== new_level
)
2915 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2916 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2917 target
->opserv_level
= new_level
;
2921 static OPTION_FUNC(opt_level
)
2926 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2930 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2931 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
2935 static OPTION_FUNC(opt_epithet
)
2937 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2939 struct userNode
*target
, *next_un
;
2942 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2946 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2950 if ((epithet
[0] == '*') && !epithet
[1])
2953 hi
->epithet
= strdup(epithet
);
2955 for (target
= hi
->users
; target
; target
= next_un
) {
2956 irc_swhois(nickserv
, target
, hi
->epithet
);
2958 next_un
= target
->next_authed
;
2963 reply("NSMSG_SET_EPITHET", hi
->epithet
);
2965 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2969 static OPTION_FUNC(opt_title
)
2975 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2977 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2982 if(!strcmp(title
, "*")) {
2984 hi
->fakehost
= NULL
;
2987 if (strchr(title
, '.')) {
2988 reply("NSMSG_TITLE_INVALID");
2991 /* Alphanumeric titles only. */
2992 for(sptr
= title
; *sptr
; sptr
++) {
2993 if(!isalnum(*sptr
) && *sptr
!= '-') {
2994 reply("NSMSG_TITLE_INVALID");
2998 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2999 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3000 reply("NSMSG_TITLE_TRUNCATED");
3004 hi
->fakehost
= malloc(strlen(title
)+2);
3005 hi
->fakehost
[0] = '.';
3006 strcpy(hi
->fakehost
+1, title
);
3009 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3010 title
= hi
->fakehost
+ 1;
3012 /* If theres no title set then the default title will therefore
3013 be the first part of hidden_host in x3.conf.example, so for
3014 consistency with opt_fakehost we will print this here */
3015 char *hs
, *hidden_suffix
, *rest
;
3017 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3018 hidden_suffix
= strdup(hs
);
3020 /* Yes we do this twice */
3021 rest
= strrchr(hidden_suffix
, '.');
3023 rest
= strrchr(hidden_suffix
, '.');
3026 title
= hidden_suffix
;
3030 none
= user_find_message(user
, "MSG_NONE");
3031 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3036 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3040 // check for a dot in the vhost
3041 if(strchr(vhost
, '.') == NULL
) {
3042 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3046 // check for a @ in the vhost
3047 if(strchr(vhost
, '@') != NULL
) {
3048 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3052 // check for denied words, inspired by monk at paki.sex
3053 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3054 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3055 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3060 // check for ircu's HOSTLEN length.
3061 if(strlen(vhost
) >= HOSTLEN
) {
3062 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3066 /* This can be handled by the regex now if desired.
3067 if (vhost[strspn(vhost, "0123456789.")]) {
3068 hostname = vhost + strlen(vhost);
3069 for (depth = 1; depth && (hostname > vhost); depth--) {
3071 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3074 if (*hostname == '.') hostname++; * advance past last dot we saw *
3075 if(strlen(hostname) > 4) {
3076 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3081 /* test either regex or as valid handle */
3082 if (nickserv_conf
.valid_fakehost_regex_set
) {
3083 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3086 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3087 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3089 if(err
== REG_NOMATCH
) {
3090 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3099 static OPTION_FUNC(opt_fakehost
)
3103 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3105 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3110 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3111 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3114 if (!strcmp(fake
, "*")) {
3117 hi
->fakehost
= NULL
;
3120 else if (!check_vhost(argv
[1], user
, cmd
)) {
3121 /* check_vhost takes care of error reply */
3127 hi
->fakehost
= strdup(fake
);
3130 fake
= hi
->fakehost
;
3132 fake
= generate_fakehost(hi
);
3134 /* Tell them we set the host */
3136 fake
= user_find_message(user
, "MSG_NONE");
3137 reply("NSMSG_SET_FAKEHOST", fake
);
3141 static OPTION_FUNC(opt_note
)
3144 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3149 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3154 if ((text
[0] == '*') && !text
[1])
3157 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3162 reply("NSMSG_SET_NOTE", hi
->note
->note
);
3166 static NICKSERV_FUNC(cmd_reclaim
)
3168 struct handle_info
*hi
;
3169 struct nick_info
*ni
;
3170 struct userNode
*victim
;
3172 NICKSERV_MIN_PARMS(2);
3173 hi
= user
->handle_info
;
3174 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3176 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3179 if (ni
->owner
!= user
->handle_info
) {
3180 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3183 victim
= GetUserH(ni
->nick
);
3185 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3188 if (victim
== user
) {
3189 reply("NSMSG_NICK_USER_YOU");
3192 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3193 switch (nickserv_conf
.reclaim_action
) {
3194 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3195 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3196 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3197 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3202 static NICKSERV_FUNC(cmd_unregnick
)
3205 struct handle_info
*hi
;
3206 struct nick_info
*ni
;
3208 hi
= user
->handle_info
;
3209 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3210 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3212 reply("NSMSG_UNKNOWN_NICK", nick
);
3215 if (hi
!= ni
->owner
) {
3216 reply("NSMSG_NOT_YOUR_NICK", nick
);
3219 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3224 static NICKSERV_FUNC(cmd_ounregnick
)
3226 struct nick_info
*ni
;
3228 NICKSERV_MIN_PARMS(2);
3229 if (!(ni
= get_nick_info(argv
[1]))) {
3230 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3233 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3234 reply("MSG_USER_OUTRANKED", ni
->nick
);
3237 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3242 static NICKSERV_FUNC(cmd_unregister
)
3244 struct handle_info
*hi
;
3247 NICKSERV_MIN_PARMS(2);
3248 hi
= user
->handle_info
;
3251 if (checkpass(passwd
, hi
->passwd
)) {
3252 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3255 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3256 reply("NSMSG_PASSWORD_INVALID");
3261 static NICKSERV_FUNC(cmd_ounregister
)
3263 struct handle_info
*hi
;
3265 NICKSERV_MIN_PARMS(2);
3266 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
3268 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3272 static NICKSERV_FUNC(cmd_status
)
3274 if (nickserv_conf
.disable_nicks
) {
3275 reply("NSMSG_GLOBAL_STATS_NONICK",
3276 dict_size(nickserv_handle_dict
));
3278 if (user
->handle_info
) {
3280 struct nick_info
*ni
;
3281 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3282 reply("NSMSG_HANDLE_STATS", cnt
);
3284 reply("NSMSG_HANDLE_NONE");
3286 reply("NSMSG_GLOBAL_STATS",
3287 dict_size(nickserv_handle_dict
),
3288 dict_size(nickserv_nick_dict
));
3293 static NICKSERV_FUNC(cmd_ghost
)
3295 struct userNode
*target
;
3296 char reason
[MAXLEN
];
3298 NICKSERV_MIN_PARMS(2);
3299 if (!(target
= GetUserH(argv
[1]))) {
3300 reply("MSG_NICK_UNKNOWN", argv
[1]);
3303 if (target
== user
) {
3304 reply("NSMSG_CANNOT_GHOST_SELF");
3307 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3308 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3311 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3312 DelUser(target
, nickserv
, 1, reason
);
3313 reply("NSMSG_GHOST_KILLED", argv
[1]);
3317 static NICKSERV_FUNC(cmd_vacation
)
3319 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3320 reply("NSMSG_ON_VACATION");
3325 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3327 struct handle_info
*hi
;
3330 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3332 saxdb_start_record(ctx
, iter_key(it
), 0);
3333 if (hi
->announcements
!= '?') {
3334 flags
[0] = hi
->announcements
;
3336 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3339 struct handle_cookie
*cookie
= hi
->cookie
;
3342 switch (cookie
->type
) {
3343 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3344 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3345 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3346 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3347 default: type
= NULL
; break;
3350 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3351 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3352 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3354 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3355 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3356 saxdb_end_record(ctx
);
3360 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3362 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3364 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3365 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3366 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3367 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3368 saxdb_end_record(ctx
);
3372 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3376 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3377 if (hi
->flags
& (1 << ii
))
3378 flags
[flen
++] = handle_flags
[ii
];
3380 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3383 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3384 if (hi
->last_quit_host
[0])
3385 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3386 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3387 if (hi
->masks
->used
)
3388 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3389 if (hi
->ignores
->used
)
3390 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3392 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3394 struct string_list
*slist
;
3395 struct nick_info
*ni
;
3397 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3398 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3399 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3403 if (hi
->opserv_level
)
3404 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3405 if (hi
->language
!= lang_C
)
3406 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3407 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3408 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3409 if (hi
->screen_width
)
3410 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3411 if (hi
->table_width
)
3412 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3413 flags
[0] = hi
->userlist_style
;
3415 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3416 saxdb_end_record(ctx
);
3422 static handle_merge_func_t
*handle_merge_func_list
;
3423 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3426 reg_handle_merge_func(handle_merge_func_t func
)
3428 if (handle_merge_func_used
== handle_merge_func_size
) {
3429 if (handle_merge_func_size
) {
3430 handle_merge_func_size
<<= 1;
3431 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3433 handle_merge_func_size
= 8;
3434 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3437 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3440 static NICKSERV_FUNC(cmd_merge
)
3442 struct handle_info
*hi_from
, *hi_to
;
3443 struct userNode
*last_user
;
3444 struct userData
*cList
, *cListNext
;
3445 unsigned int ii
, jj
, n
;
3447 NICKSERV_MIN_PARMS(3);
3449 if (!(hi_from
= get_victim_oper(cmd
, user
, argv
[1])))
3451 if (!(hi_to
= get_victim_oper(cmd
, user
, argv
[2])))
3453 if (hi_to
== hi_from
) {
3454 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3458 for (n
=0; n
<handle_merge_func_used
; n
++)
3459 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3461 /* Append "from" handle's nicks to "to" handle's nick list. */
3463 struct nick_info
*last_ni
;
3464 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3465 last_ni
->next
= hi_from
->nicks
;
3467 while (hi_from
->nicks
) {
3468 hi_from
->nicks
->owner
= hi_to
;
3469 hi_from
->nicks
= hi_from
->nicks
->next
;
3472 /* Merge the hostmasks. */
3473 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3474 char *mask
= hi_from
->masks
->list
[ii
];
3475 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3476 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3478 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3479 string_list_append(hi_to
->masks
, strdup(mask
));
3482 /* Merge the ignores. */
3483 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3484 char *ignore
= hi_from
->ignores
->list
[ii
];
3485 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3486 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3488 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3489 string_list_append(hi_to
->ignores
, strdup(ignore
));
3492 /* Merge the lists of authed users. */
3494 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3495 last_user
->next_authed
= hi_from
->users
;
3497 hi_to
->users
= hi_from
->users
;
3499 /* Repoint the old "from" handle's users. */
3500 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3501 last_user
->handle_info
= hi_to
;
3503 hi_from
->users
= NULL
;
3505 /* Merge channel userlists. */
3506 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3507 struct userData
*cList2
;
3508 cListNext
= cList
->u_next
;
3509 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3510 if (cList
->channel
== cList2
->channel
)
3512 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3513 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
);
3514 /* keep cList2 in hi_to; remove cList from hi_from */
3515 del_channel_user(cList
, 1);
3518 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
);
3519 /* remove the lower-ranking cList2 from hi_to */
3520 del_channel_user(cList2
, 1);
3522 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3524 /* cList needs to be moved from hi_from to hi_to */
3525 cList
->handle
= hi_to
;
3526 /* Remove from linked list for hi_from */
3527 assert(!cList
->u_prev
);
3528 hi_from
->channels
= cList
->u_next
;
3530 cList
->u_next
->u_prev
= cList
->u_prev
;
3531 /* Add to linked list for hi_to */
3532 cList
->u_prev
= NULL
;
3533 cList
->u_next
= hi_to
->channels
;
3534 if (hi_to
->channels
)
3535 hi_to
->channels
->u_prev
= cList
;
3536 hi_to
->channels
= cList
;
3540 /* Do they get an OpServ level promotion? */
3541 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3542 hi_to
->opserv_level
= hi_from
->opserv_level
;
3544 /* What about last seen time? */
3545 if (hi_from
->lastseen
> hi_to
->lastseen
)
3546 hi_to
->lastseen
= hi_from
->lastseen
;
3548 /* Does a fakehost carry over? (This intentionally doesn't set it
3549 * for users previously attached to hi_to. They'll just have to
3552 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3553 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3555 /* Notify of success. */
3556 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3557 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
3558 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3560 /* Unregister the "from" handle. */
3561 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3566 struct nickserv_discrim
{
3567 unsigned int limit
, min_level
, max_level
;
3568 unsigned long flags_on
, flags_off
;
3569 time_t min_registered
, max_registered
;
3571 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3572 const char *nickmask
;
3573 const char *hostmask
;
3574 const char *handlemask
;
3575 const char *emailmask
;
3578 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3580 struct discrim_apply_info
{
3581 struct nickserv_discrim
*discrim
;
3582 discrim_search_func func
;
3583 struct userNode
*source
;
3584 unsigned int matched
;
3587 static struct nickserv_discrim
*
3588 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
3591 struct nickserv_discrim
*discrim
;
3593 discrim
= malloc(sizeof(*discrim
));
3594 memset(discrim
, 0, sizeof(*discrim
));
3595 discrim
->min_level
= 0;
3596 discrim
->max_level
= ~0;
3597 discrim
->limit
= 50;
3598 discrim
->min_registered
= 0;
3599 discrim
->max_registered
= INT_MAX
;
3600 discrim
->lastseen
= now
;
3602 for (i
=0; i
<argc
; i
++) {
3603 if (i
== argc
- 1) {
3604 reply("MSG_MISSING_PARAMS", argv
[i
]);
3607 if (!irccasecmp(argv
[i
], "limit")) {
3608 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3609 } else if (!irccasecmp(argv
[i
], "flags")) {
3610 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3611 } else if (!irccasecmp(argv
[i
], "registered")) {
3612 const char *cmp
= argv
[++i
];
3613 if (cmp
[0] == '<') {
3614 if (cmp
[1] == '=') {
3615 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3617 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3619 } else if (cmp
[0] == '=') {
3620 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3621 } else if (cmp
[0] == '>') {
3622 if (cmp
[1] == '=') {
3623 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3625 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3628 reply("MSG_INVALID_CRITERIA", cmp
);
3630 } else if (!irccasecmp(argv
[i
], "seen")) {
3631 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3632 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3633 discrim
->nickmask
= argv
[++i
];
3634 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3636 if (!irccasecmp(argv
[i
], "exact")) {
3637 if (i
== argc
- 1) {
3638 reply("MSG_MISSING_PARAMS", argv
[i
]);
3641 discrim
->hostmask_type
= EXACT
;
3642 } else if (!irccasecmp(argv
[i
], "subset")) {
3643 if (i
== argc
- 1) {
3644 reply("MSG_MISSING_PARAMS", argv
[i
]);
3647 discrim
->hostmask_type
= SUBSET
;
3648 } else if (!irccasecmp(argv
[i
], "superset")) {
3649 if (i
== argc
- 1) {
3650 reply("MSG_MISSING_PARAMS", argv
[i
]);
3653 discrim
->hostmask_type
= SUPERSET
;
3654 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3655 if (i
== argc
- 1) {
3656 reply("MSG_MISSING_PARAMS", argv
[i
]);
3659 discrim
->hostmask_type
= LASTQUIT
;
3662 discrim
->hostmask_type
= SUPERSET
;
3664 discrim
->hostmask
= argv
[++i
];
3665 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3666 if (!irccasecmp(argv
[++i
], "*")) {
3667 discrim
->handlemask
= 0;
3669 discrim
->handlemask
= argv
[i
];
3671 } else if (!irccasecmp(argv
[i
], "email")) {
3672 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3673 reply("MSG_NO_SEARCH_ACCESS", "email");
3675 } else if (!irccasecmp(argv
[++i
], "*")) {
3676 discrim
->emailmask
= 0;
3678 discrim
->emailmask
= argv
[i
];
3680 } else if (!irccasecmp(argv
[i
], "access")) {
3681 const char *cmp
= argv
[++i
];
3682 if (cmp
[0] == '<') {
3683 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3684 if (cmp
[1] == '=') {
3685 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3687 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3689 } else if (cmp
[0] == '=') {
3690 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3691 } else if (cmp
[0] == '>') {
3692 if (cmp
[1] == '=') {
3693 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3695 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3698 reply("MSG_INVALID_CRITERIA", cmp
);
3701 reply("MSG_INVALID_CRITERIA", argv
[i
]);
3712 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3714 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3715 || (discrim
->flags_off
& hi
->flags
)
3716 || (discrim
->min_registered
> hi
->registered
)
3717 || (discrim
->max_registered
< hi
->registered
)
3718 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3719 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3720 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3721 || (discrim
->min_level
> hi
->opserv_level
)
3722 || (discrim
->max_level
< hi
->opserv_level
)) {
3725 if (discrim
->hostmask
) {
3727 for (i
=0; i
<hi
->masks
->used
; i
++) {
3728 const char *mask
= hi
->masks
->list
[i
];
3729 if ((discrim
->hostmask_type
== SUBSET
)
3730 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3731 else if ((discrim
->hostmask_type
== EXACT
)
3732 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3733 else if ((discrim
->hostmask_type
== SUPERSET
)
3734 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3735 else if ((discrim
->hostmask_type
== LASTQUIT
)
3736 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3738 if (i
==hi
->masks
->used
) return 0;
3740 if (discrim
->nickmask
) {
3741 struct nick_info
*nick
= hi
->nicks
;
3743 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3746 if (!nick
) return 0;
3752 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3754 dict_iterator_t it
, next
;
3755 unsigned int matched
;
3757 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3758 it
&& (matched
< discrim
->limit
);
3760 next
= iter_next(it
);
3761 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3762 dsf(source
, iter_data(it
));
3770 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3772 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3776 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3781 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3783 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3784 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3788 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3790 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3791 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3792 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3793 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3794 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3798 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3800 struct handle_info_list hil
;
3801 struct helpfile_table tbl
;
3806 memset(&hil
, 0, sizeof(hil
));
3807 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3808 struct handle_info
*hi
= iter_data(it
);
3809 if (hi
->opserv_level
)
3810 handle_info_list_append(&hil
, hi
);
3812 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3813 tbl
.length
= hil
.used
+ 1;
3815 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
3816 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3817 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3820 for (ii
= 0; ii
< hil
.used
; ) {
3821 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3822 ary
[0] = hil
.list
[ii
]->handle
;
3823 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3824 tbl
.contents
[++ii
] = ary
;
3826 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3827 /*reply("MSG_MATCH_COUNT", hil.used); */
3828 for (ii
= 0; ii
< hil
.used
; ii
++)
3829 free(tbl
.contents
[ii
]);
3834 static NICKSERV_FUNC(cmd_search
)
3836 struct nickserv_discrim
*discrim
;
3837 discrim_search_func action
;
3838 struct svccmd
*subcmd
;
3839 unsigned int matches
;
3842 NICKSERV_MIN_PARMS(3);
3843 sprintf(buf
, "search %s", argv
[1]);
3844 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3845 if (!irccasecmp(argv
[1], "print"))
3846 action
= search_print_func
;
3847 else if (!irccasecmp(argv
[1], "count"))
3848 action
= search_count_func
;
3849 else if (!irccasecmp(argv
[1], "unregister"))
3850 action
= search_unregister_func
;
3852 reply("NSMSG_INVALID_ACTION", argv
[1]);
3856 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3859 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
3863 if (action
== search_print_func
)
3864 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3865 else if (action
== search_count_func
)
3866 discrim
->limit
= INT_MAX
;
3868 matches
= nickserv_discrim_search(discrim
, action
, user
);
3871 reply("MSG_MATCH_COUNT", matches
);
3873 reply("MSG_NO_MATCHES");
3879 static MODCMD_FUNC(cmd_checkpass
)
3881 struct handle_info
*hi
;
3883 NICKSERV_MIN_PARMS(3);
3884 if (!(hi
= get_handle_info(argv
[1]))) {
3885 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3888 if (checkpass(argv
[2], hi
->passwd
))
3889 reply("CHECKPASS_YES");
3891 reply("CHECKPASS_NO");
3897 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3900 struct string_list
*masks
, *slist
, *ignores
;
3901 struct handle_info
*hi
;
3902 struct userNode
*authed_users
;
3903 struct userData
*channels
;
3904 unsigned long int id
;
3907 char *setter
, *note
;
3910 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3911 id
= str
? strtoul(str
, NULL
, 0) : 0;
3912 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3914 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3917 if ((hi
= get_handle_info(handle
))) {
3918 authed_users
= hi
->users
;
3919 channels
= hi
->channels
;
3921 hi
->channels
= NULL
;
3922 dict_remove(nickserv_handle_dict
, hi
->handle
);
3924 authed_users
= NULL
;
3927 hi
= register_handle(handle
, str
, id
);
3929 hi
->users
= authed_users
;
3930 while (authed_users
) {
3931 authed_users
->handle_info
= hi
;
3932 authed_users
= authed_users
->next_authed
;
3935 hi
->channels
= channels
;
3936 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3937 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3938 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
3939 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
3940 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3941 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3942 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3943 hi
->language
= language_find(str
? str
: "C");
3944 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3945 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3946 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3948 hi
->infoline
= strdup(str
);
3949 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3950 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3951 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3952 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3953 /* We want to read the nicks even if disable_nicks is set. This is so
3954 * that we don't lose the nick data entirely. */
3955 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3957 for (ii
=0; ii
<slist
->used
; ii
++)
3958 register_nick(slist
->list
[ii
], hi
);
3960 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3962 for (ii
=0; str
[ii
]; ii
++)
3963 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3965 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3966 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3967 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3968 hi
->announcements
= str
? str
[0] : '?';
3969 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3970 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3971 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3972 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3973 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3975 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3977 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3978 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3980 nickserv_set_email_addr(hi
, str
);
3981 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3983 hi
->epithet
= strdup(str
);
3984 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3986 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3987 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3988 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3989 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3990 if (setter
&& date
&& note
)
3992 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3997 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3999 hi
->fakehost
= strdup(str
);
4001 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4003 const char *data
, *type
, *expires
, *cookie_str
;
4004 struct handle_cookie
*cookie
;
4006 cookie
= calloc(1, sizeof(*cookie
));
4007 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4008 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4009 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4010 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4011 if (!type
|| !expires
|| !cookie_str
) {
4012 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4015 if (!irccasecmp(type
, KEY_ACTIVATION
))
4016 cookie
->type
= ACTIVATION
;
4017 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4018 cookie
->type
= PASSWORD_CHANGE
;
4019 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4020 cookie
->type
= EMAIL_CHANGE
;
4021 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4022 cookie
->type
= ALLOWAUTH
;
4024 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4027 cookie
->expires
= strtoul(expires
, NULL
, 0);
4028 if (cookie
->expires
< now
)
4031 cookie
->data
= strdup(data
);
4032 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4036 nickserv_bake_cookie(cookie
);
4038 nickserv_free_cookie(cookie
);
4043 nickserv_saxdb_read(dict_t db
) {
4045 struct record_data
*rd
;
4047 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4049 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
4054 static NICKSERV_FUNC(cmd_mergedb
)
4056 struct timeval start
, stop
;
4059 NICKSERV_MIN_PARMS(2);
4060 gettimeofday(&start
, NULL
);
4061 if (!(db
= parse_database(argv
[1]))) {
4062 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4065 nickserv_saxdb_read(db
);
4067 gettimeofday(&stop
, NULL
);
4068 stop
.tv_sec
-= start
.tv_sec
;
4069 stop
.tv_usec
-= start
.tv_usec
;
4070 if (stop
.tv_usec
< 0) {
4072 stop
.tv_usec
+= 1000000;
4074 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4079 expire_handles(UNUSED_ARG(void *data
))
4081 dict_iterator_t it
, next
;
4083 struct handle_info
*hi
;
4085 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4086 next
= iter_next(it
);
4088 if ((hi
->opserv_level
> 0)
4090 || HANDLE_FLAGGED(hi
, FROZEN
)
4091 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4094 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4095 if ((now
- hi
->lastseen
) > expiry
) {
4096 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4097 nickserv_unregister_handle(hi
, NULL
, NULL
);
4101 if (nickserv_conf
.handle_expire_frequency
)
4102 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4106 nickserv_load_dict(const char *fname
)
4110 if (!(file
= fopen(fname
, "r"))) {
4111 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4114 while (!feof(file
)) {
4115 fgets(line
, sizeof(line
), file
);
4118 if (line
[strlen(line
)-1] == '\n')
4119 line
[strlen(line
)-1] = 0;
4120 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4123 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4126 static enum reclaim_action
4127 reclaim_action_from_string(const char *str
) {
4129 return RECLAIM_NONE
;
4130 else if (!irccasecmp(str
, "warn"))
4131 return RECLAIM_WARN
;
4132 else if (!irccasecmp(str
, "svsnick"))
4133 return RECLAIM_SVSNICK
;
4134 else if (!irccasecmp(str
, "kill"))
4135 return RECLAIM_KILL
;
4137 return RECLAIM_NONE
;
4141 nickserv_conf_read(void)
4143 dict_t conf_node
, child
;
4146 struct string_list
*strlist
;
4148 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4149 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4152 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4154 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4155 if (nickserv_conf
.valid_handle_regex_set
)
4156 regfree(&nickserv_conf
.valid_handle_regex
);
4158 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4159 nickserv_conf
.valid_handle_regex_set
= !err
;
4160 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4162 nickserv_conf
.valid_handle_regex_set
= 0;
4164 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4165 if (nickserv_conf
.valid_nick_regex_set
)
4166 regfree(&nickserv_conf
.valid_nick_regex
);
4168 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4169 nickserv_conf
.valid_nick_regex_set
= !err
;
4170 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4172 nickserv_conf
.valid_nick_regex_set
= 0;
4174 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4175 if (nickserv_conf
.valid_fakehost_regex_set
)
4176 regfree(&nickserv_conf
.valid_fakehost_regex
);
4178 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4179 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4180 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4182 nickserv_conf
.valid_fakehost_regex_set
= 0;
4184 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4186 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4187 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4188 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4189 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4190 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4191 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4192 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4193 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4194 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4195 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4196 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4197 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4198 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4199 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4200 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4201 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4202 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4203 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4204 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4205 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4206 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4207 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4208 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4209 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4210 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4212 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4213 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4214 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4216 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4217 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4218 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4220 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4221 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4222 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4223 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4224 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4225 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4226 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4227 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4228 if (!nickserv_conf
.disable_nicks
) {
4229 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4230 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4231 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4232 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4233 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4234 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4235 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4236 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4238 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4239 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4240 const char *key
= iter_key(it
), *value
;
4244 if (!strncasecmp(key
, "uc_", 3))
4245 flag
= toupper(key
[3]);
4246 else if (!strncasecmp(key
, "lc_", 3))
4247 flag
= tolower(key
[3]);
4251 if ((pos
= handle_inverse_flags
[flag
])) {
4252 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4253 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4256 if (nickserv_conf
.weak_password_dict
)
4257 dict_delete(nickserv_conf
.weak_password_dict
);
4258 nickserv_conf
.weak_password_dict
= dict_new();
4259 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4260 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4261 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4262 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4264 nickserv_load_dict(str
);
4265 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4266 if (nickserv
&& str
)
4267 NickChange(nickserv
, str
, 0);
4268 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4269 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4270 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4271 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4272 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4273 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4274 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4275 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4276 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4277 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4278 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4279 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4280 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4281 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4282 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4283 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4284 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4285 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4286 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4287 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4289 free_string_list(nickserv_conf
.denied_fakehost_words
);
4290 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4292 strlist
= string_list_copy(strlist
);
4294 strlist
= alloc_string_list(4);
4295 string_list_append(strlist
, strdup("sex"));
4296 string_list_append(strlist
, strdup("fuck"));
4298 nickserv_conf
.denied_fakehost_words
= strlist
;
4300 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4301 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4303 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4304 nickserv_conf
.auto_oper
= str
? str
: "";
4306 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4307 nickserv_conf
.auto_admin
= str
? str
: "";
4309 str
= conf_get_data("server/network", RECDB_QSTRING
);
4310 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4311 if (!nickserv_conf
.auth_policer_params
) {
4312 nickserv_conf
.auth_policer_params
= policer_params_new();
4313 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4314 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4316 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4317 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4318 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4322 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4324 char newnick
[NICKLEN
+1];
4333 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4335 case RECLAIM_SVSNICK
:
4337 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4338 } while (GetUserH(newnick
));
4339 irc_svsnick(nickserv
, user
, newnick
);
4342 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4343 irc_kill(nickserv
, user
, msg
);
4349 nickserv_reclaim_p(void *data
) {
4350 struct userNode
*user
= data
;
4351 struct nick_info
*ni
= get_nick_info(user
->nick
);
4353 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4357 check_user_nick(struct userNode
*user
) {
4358 struct nick_info
*ni
;
4359 user
->modes
&= ~FLAGS_REGNICK
;
4360 if (!(ni
= get_nick_info(user
->nick
)))
4362 if (user
->handle_info
== ni
->owner
) {
4363 user
->modes
|= FLAGS_REGNICK
;
4367 if (nickserv_conf
.warn_nick_owned
)
4368 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4369 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4371 if (nickserv_conf
.auto_reclaim_delay
)
4372 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4374 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4379 handle_new_user(struct userNode
*user
)
4381 return check_user_nick(user
);
4385 handle_account(struct userNode
*user
, const char *stamp
)
4387 struct handle_info
*hi
;
4390 #ifdef WITH_PROTOCOL_P10
4391 time_t timestamp
= 0;
4393 colon
= strchr(stamp
, ':');
4394 if(colon
&& colon
[1])
4397 timestamp
= atoi(colon
+1);
4399 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4400 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4402 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
);
4406 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4407 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4411 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4414 set_user_handle_info(user
, hi
, 0);
4416 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4421 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4423 struct handle_info
*hi
;
4425 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4426 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4427 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4429 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4430 check_user_nick(user
);
4434 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4436 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4437 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4438 set_user_handle_info(user
, NULL
, 0);
4441 static struct modcmd
*
4442 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4444 if (min_level
> 0) {
4446 sprintf(buf
, "%u", min_level
);
4447 if (must_be_qualified
) {
4448 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4450 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4452 } else if (min_level
== 0) {
4453 if (must_be_qualified
) {
4454 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4456 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4459 if (must_be_qualified
) {
4460 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4462 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4468 nickserv_db_cleanup(void)
4470 unreg_del_user_func(nickserv_remove_user
);
4471 userList_clean(&curr_helpers
);
4472 policer_params_delete(nickserv_conf
.auth_policer_params
);
4473 dict_delete(nickserv_handle_dict
);
4474 dict_delete(nickserv_nick_dict
);
4475 dict_delete(nickserv_opt_dict
);
4476 dict_delete(nickserv_allow_auth_dict
);
4477 dict_delete(nickserv_email_dict
);
4478 dict_delete(nickserv_id_dict
);
4479 dict_delete(nickserv_conf
.weak_password_dict
);
4480 free(auth_func_list
);
4481 free(unreg_func_list
);
4483 free(allowauth_func_list
);
4484 free(handle_merge_func_list
);
4485 free(failpw_func_list
);
4486 if (nickserv_conf
.valid_handle_regex_set
)
4487 regfree(&nickserv_conf
.valid_handle_regex
);
4488 if (nickserv_conf
.valid_nick_regex_set
)
4489 regfree(&nickserv_conf
.valid_nick_regex
);
4493 init_nickserv(const char *nick
)
4495 struct chanNode
*chan
;
4497 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4498 reg_new_user_func(handle_new_user
);
4499 reg_nick_change_func(handle_nick_change
);
4500 reg_del_user_func(nickserv_remove_user
);
4501 reg_account_func(handle_account
);
4503 /* set up handle_inverse_flags */
4504 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4505 for (i
=0; handle_flags
[i
]; i
++) {
4506 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4507 flag_access_levels
[i
] = 0;
4510 conf_register_reload(nickserv_conf_read
);
4511 nickserv_opt_dict
= dict_new();
4512 nickserv_email_dict
= dict_new();
4514 dict_set_free_keys(nickserv_email_dict
, free
);
4515 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4517 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4518 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4519 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4520 * a big pain to disable since its nolonger in the config file. ) -Rubin
4522 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4523 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4524 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4525 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4526 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4527 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4528 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4529 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4530 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4531 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4532 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4533 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4534 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4535 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4536 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4537 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4538 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4539 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4540 if (!nickserv_conf
.disable_nicks
) {
4541 /* nick management commands */
4542 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4543 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4544 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4545 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4546 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4547 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4549 if (nickserv_conf
.email_enabled
) {
4550 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4551 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4552 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4553 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4554 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4555 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4557 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4558 /* ignore commands */
4559 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
4560 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
4561 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
4562 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
4563 /* miscellaneous commands */
4564 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4565 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4566 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4567 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4568 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4570 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4571 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4572 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4573 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4574 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4575 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4576 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4577 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4578 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4579 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4580 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4581 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4582 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4583 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4584 if (nickserv_conf
.titlehost_suffix
) {
4585 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4586 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4588 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4589 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4590 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
4591 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4593 nickserv_handle_dict
= dict_new();
4594 dict_set_free_keys(nickserv_handle_dict
, free
);
4595 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4597 nickserv_id_dict
= dict_new();
4598 dict_set_free_keys(nickserv_id_dict
, free
);
4600 nickserv_nick_dict
= dict_new();
4601 dict_set_free_data(nickserv_nick_dict
, free
);
4603 nickserv_allow_auth_dict
= dict_new();
4605 userList_init(&curr_helpers
);
4608 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4609 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4610 nickserv_service
= service_register(nickserv
);
4612 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4613 reg_exit_func(nickserv_db_cleanup
);
4614 if(nickserv_conf
.handle_expire_frequency
)
4615 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4617 if(autojoin_channels
&& nickserv
) {
4618 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
4619 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
4620 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
4624 message_register_table(msgtab
);