1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
34 #define NICKSERV_CONF_NAME "services/nickserv"
36 #define KEY_DISABLE_NICKS "disable_nicks"
37 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
38 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
39 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
40 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
41 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
42 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
43 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
44 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
45 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
46 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
47 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
48 #define KEY_MODOPER_LEVEL "modoper_level"
49 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
50 #define KEY_SET_TITLE_LEVEL "set_title_level"
51 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
52 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
53 #define KEY_AUTO_OPER "auto_oper"
54 #define KEY_AUTO_ADMIN "auto_admin"
55 #define KEY_FLAG_LEVELS "flag_levels"
56 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
57 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
58 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
59 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
60 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
61 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
62 #define KEY_DICT_FILE "dict_file"
63 #define KEY_NICK "nick"
64 #define KEY_LANGUAGE "language"
65 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
66 #define KEY_AUTOGAG_DURATION "autogag_duration"
67 #define KEY_AUTH_POLICER "auth_policer"
68 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
69 #define KEY_EMAIL_ENABLED "email_enabled"
70 #define KEY_EMAIL_REQUIRED "email_required"
71 #define KEY_SYNC_LOG "sync_log"
72 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
73 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
74 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
77 #define KEY_PASSWD "passwd"
78 #define KEY_NICKS "nicks"
79 #define KEY_MASKS "masks"
80 #define KEY_OPSERV_LEVEL "opserv_level"
81 #define KEY_FLAGS "flags"
82 #define KEY_REGISTER_ON "register"
83 #define KEY_LAST_SEEN "lastseen"
84 #define KEY_INFO "info"
85 #define KEY_USERLIST_STYLE "user_style"
86 #define KEY_SCREEN_WIDTH "screen_width"
87 #define KEY_LAST_AUTHED_HOST "last_authed_host"
88 #define KEY_LAST_QUIT_HOST "last_quit_host"
89 #define KEY_EMAIL_ADDR "email_addr"
90 #define KEY_COOKIE "cookie"
91 #define KEY_COOKIE_DATA "data"
92 #define KEY_COOKIE_TYPE "type"
93 #define KEY_COOKIE_EXPIRES "expires"
94 #define KEY_ACTIVATION "activation"
95 #define KEY_PASSWORD_CHANGE "password change"
96 #define KEY_EMAIL_CHANGE "email change"
97 #define KEY_ALLOWAUTH "allowauth"
98 #define KEY_EPITHET "epithet"
99 #define KEY_TABLE_WIDTH "table_width"
100 #define KEY_ANNOUNCEMENTS "announcements"
101 #define KEY_MAXLOGINS "maxlogins"
102 #define KEY_FAKEHOST "fakehost"
103 #define KEY_NOTE_NOTE "note"
104 #define KEY_NOTE_SETTER "setter"
105 #define KEY_NOTE_DATE "date"
108 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
110 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
111 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
112 typedef OPTION_FUNC(option_func_t
);
114 DEFINE_LIST(handle_info_list
, struct handle_info
*);
116 #define NICKSERV_MIN_PARMS(N) do { \
118 reply("MSG_MISSING_PARAMS", argv[0]); \
119 svccmd_send_help_brief(user, nickserv, cmd); \
123 struct userNode
*nickserv
;
124 struct userList curr_helpers
;
125 const char *handle_flags
= HANDLE_FLAGS
;
127 static struct module *nickserv_module
;
128 static struct service
*nickserv_service
;
129 static struct log_type
*NS_LOG
;
130 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
131 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
132 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
133 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
134 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
135 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
136 static char handle_inverse_flags
[256];
137 static unsigned int flag_access_levels
[32];
138 static const struct message_entry msgtab
[] = {
139 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
140 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
141 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
142 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
143 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
144 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
145 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
146 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
147 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
148 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
149 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
150 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
151 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
152 { "NSMSG_USE_COOKIE_REGISTER", "To activate your account, you must check your email for the \"cookie\" that has been mailed to it. When you have it, use the $bcookie$b command to complete registration." },
153 { "NSMSG_USE_COOKIE_RESETPASS", "A cookie has been mailed to your account's email address. You must check your email and use the $bcookie$b command to confirm the password change." },
154 { "NSMSG_USE_COOKIE_EMAIL_1", "A cookie has been mailed to the new address you requested. To finish setting your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
155 { "NSMSG_USE_COOKIE_EMAIL_2", "A cookie has been generated, and half mailed to each your old and new addresses. To finish changing your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
156 { "NSMSG_USE_COOKIE_AUTH", "A cookie has been generated and sent to your email address. Once you have checked your email and received the cookie, auth using the $bcookie$b command." },
157 { "NSMSG_COOKIE_LIVE", "Account $b%s$b already has a cookie active. Please either finish using that cookie, wait for it to expire, or auth to the account and use the $bdelcookie$b command." },
158 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
159 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
160 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
161 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
162 { "NSMSG_BAD_COOKIE", "That cookie is not the right one. Please make sure you are copying it EXACTLY from the email; it is case-sensitive, so $bABC$b is different from $babc$b." },
163 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
164 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
165 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
166 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
167 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
168 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
169 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
170 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
171 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
172 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
173 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
174 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
175 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
176 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
177 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
178 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
179 { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%1$s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %1$s)" },
180 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
181 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
182 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
183 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
184 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
185 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
186 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
187 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
188 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
189 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
190 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
191 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
192 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
193 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
194 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
195 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
196 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
197 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
198 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
199 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
200 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
201 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
202 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
203 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
204 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
205 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
206 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
207 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
208 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
209 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
210 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
211 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
212 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
213 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
214 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
215 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
216 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
217 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
218 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
219 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
220 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
221 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
222 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
223 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
224 { "NSMSG_WEAK_PASSWORD", "WARNING: You are using a password that is considered weak (easy to guess). It is STRONGLY recommended you change it (now, if not sooner) by typing \"/msg $S@$s PASS oldpass newpass\" (with your current password and a new password)." },
225 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
226 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
227 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
228 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
229 { "NSMSG_AUTH_ALLOWED_MSG", "You may now authenticate to account $b%s$b by typing $b/msg $N@$s auth %s password$b (using your password). If you will be using this computer regularly, please type $b/msg $N addmask$b (AFTER you auth) to permanently add your hostmask." },
230 { "NSMSG_AUTH_ALLOWED_EMAIL", "You may also (after you auth) type $b/msg $N set email user@your.isp$b to set an email address. This will let you use the $bauthcookie$b command to be authenticated in the future." },
231 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
232 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
233 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
234 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
235 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
236 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
237 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
238 { "NSMSG_PASS_SUCCESS", "Password changed." },
239 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
240 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
241 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
242 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
243 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
244 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
245 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
246 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
247 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
248 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
249 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
250 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
251 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
252 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
253 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
254 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
255 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
256 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
257 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
258 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
259 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
260 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
261 { "NSMSG_NO_ACCESS", "Access denied." },
262 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
263 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
264 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
265 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
266 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
267 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
268 { "NSMSG_BAD_HANDLE", "Account $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
269 { "NSMSG_BAD_NICK", "Nickname $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
270 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
271 { "NSMSG_FAIL_RENAME", "Account $b%s$b not renamed to $b%s$b because it is in use by a network services, or contains invalid characters." },
272 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
273 { "NSMSG_SEARCH_MATCH", "Match: %s" },
274 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
275 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
276 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
277 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
278 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
279 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
280 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
281 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
282 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
283 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
284 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
285 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
286 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
287 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
288 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
289 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
290 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
291 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
292 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
293 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
294 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
295 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
296 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
297 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
298 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
299 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
300 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
301 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
302 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
303 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
304 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
305 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
306 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
308 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
309 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
311 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
312 { "NSEMAIL_ACTIVATION_BODY",
313 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
315 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
316 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
317 "This command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n"
318 "/msg %3$s@%4$s AUTH %5$s your-password\n"
319 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
320 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
322 "If you did NOT request this account, you do not need to do anything.\n"
323 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
324 { "NSEMAIL_ACTIVATION_BODY_WEB",
325 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
327 "To verify your email address and complete the account registration, visit the following URL:\n"
328 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
330 "If you did NOT request this account, you do not need to do anything.\n"
331 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
332 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
333 { "NSEMAIL_PASSWORD_CHANGE_BODY",
334 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
335 "To complete the password change, log on to %1$s and type the following command:\n"
336 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
337 "If you did NOT request your password to be changed, you do not need to do anything.\n"
338 "Please contact the %1$s staff if you have questions." },
339 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
340 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
341 "To complete the password change, click the following URL:\n"
342 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
343 "If you did NOT request your password to be changed, you do not need to do anything.\n"
344 "Please contact the %1$s staff if you have questions." },
345 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
346 #ifdef stupid_verify_old_email
347 { "NSEMAIL_EMAIL_CHANGE_BODY_NEW", "This email has been sent to verify that your email address belongs to the same person as account %5$s on %1$s. The SECOND HALF of your cookie is %2$.*6$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s ?????%2$.*6$s\n(Replace the ????? with the FIRST HALF of the cookie, as sent to your OLD email address.)\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
348 { "NSEMAIL_EMAIL_CHANGE_BODY_OLD", "This email has been sent to verify that you want to change your email for account %5$s on %1$s from this address to %7$s. The FIRST HALF of your cookie is %2$.*6$s\nTo verify your new address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$.*6$s?????\n(Replace the ????? with the SECOND HALF of the cookie, as sent to your NEW email address.)\nIf you did NOT request this change of email address, you do not need to do anything. Please contact the %1$s staff if you have questions." },
350 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
351 { "NSEMAIL_EMAIL_VERIFY_BODY", "This email has been sent to verify that this address belongs to the same person as %5$s on %1$s. Your cookie is %2$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
352 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
353 { "NSEMAIL_ALLOWAUTH_BODY", "This email has been sent to let you authenticate (auth) to account %5$s on %1$s. Your cookie is %2$s.\nTo auth to that account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this authorization, you do not need to do anything. Please contact the %1$s staff if you have questions." },
354 { "CHECKPASS_YES", "Yes." },
355 { "CHECKPASS_NO", "No." },
359 enum reclaim_action
{
365 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
366 static void nickserv_reclaim_p(void *data
);
369 unsigned int disable_nicks
: 1;
370 unsigned int valid_handle_regex_set
: 1;
371 unsigned int valid_nick_regex_set
: 1;
372 unsigned int autogag_enabled
: 1;
373 unsigned int email_enabled
: 1;
374 unsigned int email_required
: 1;
375 unsigned int default_hostmask
: 1;
376 unsigned int warn_nick_owned
: 1;
377 unsigned int warn_clone_auth
: 1;
378 unsigned int sync_log
: 1;
379 unsigned long nicks_per_handle
;
380 unsigned long password_min_length
;
381 unsigned long password_min_digits
;
382 unsigned long password_min_upper
;
383 unsigned long password_min_lower
;
384 unsigned long db_backup_frequency
;
385 unsigned long handle_expire_frequency
;
386 unsigned long autogag_duration
;
387 unsigned long email_visible_level
;
388 unsigned long cookie_timeout
;
389 unsigned long handle_expire_delay
;
390 unsigned long nochan_handle_expire_delay
;
391 unsigned long modoper_level
;
392 unsigned long set_epithet_level
;
393 unsigned long set_title_level
;
394 unsigned long set_fakehost_level
;
395 unsigned long handles_per_email
;
396 unsigned long email_search_level
;
397 const char *network_name
;
398 const char *titlehost_suffix
;
399 regex_t valid_handle_regex
;
400 regex_t valid_nick_regex
;
401 dict_t weak_password_dict
;
402 struct policer_params
*auth_policer_params
;
403 enum reclaim_action reclaim_action
;
404 enum reclaim_action auto_reclaim_action
;
405 unsigned long auto_reclaim_delay
;
406 unsigned char default_maxlogins
;
407 unsigned char hard_maxlogins
;
408 const char *auto_oper
;
409 const char *auto_admin
;
412 /* We have 2^32 unique account IDs to use. */
413 unsigned long int highest_id
= 0;
416 canonicalize_hostmask(char *mask
)
418 char *out
= mask
, *temp
;
419 if ((temp
= strchr(mask
, '!'))) {
421 while (*temp
) *out
++ = *temp
++;
427 static struct handle_note
*
428 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
430 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
432 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
434 memcpy(note
->note
, text
, strlen(text
));
438 static struct handle_info
*
439 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
441 struct handle_info
*hi
;
443 #ifdef WITH_PROTOCOL_BAHAMUT
444 char id_base64
[IDLEN
+ 1];
447 /* Assign a unique account ID to the account; note that 0 is
448 an invalid account ID. 1 is therefore the first account ID. */
450 id
= 1 + highest_id
++;
452 /* Note: highest_id is and must always be the highest ID. */
453 if(id
> highest_id
) {
457 inttobase64(id_base64
, id
, IDLEN
);
459 /* Make sure an account with the same ID doesn't exist. If a
460 duplicate is found, log some details and assign a new one.
461 This should be impossible, but it never hurts to expect it. */
462 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
463 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
469 hi
= calloc(1, sizeof(*hi
));
470 hi
->userlist_style
= HI_DEFAULT_STYLE
;
471 hi
->announcements
= '?';
472 hi
->handle
= strdup(handle
);
473 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
475 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
477 #ifdef WITH_PROTOCOL_BAHAMUT
479 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
486 register_nick(const char *nick
, struct handle_info
*owner
)
488 struct nick_info
*ni
;
489 ni
= malloc(sizeof(struct nick_info
));
490 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
492 ni
->next
= owner
->nicks
;
494 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
498 delete_nick(struct nick_info
*ni
)
500 struct nick_info
*last
, *next
;
501 struct userNode
*user
;
502 /* Check to see if we should mark a user as unregistered. */
503 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
504 user
->modes
&= ~FLAGS_REGNICK
;
507 /* Remove ni from the nick_info linked list. */
508 if (ni
== ni
->owner
->nicks
) {
509 ni
->owner
->nicks
= ni
->next
;
511 last
= ni
->owner
->nicks
;
517 last
->next
= next
->next
;
519 dict_remove(nickserv_nick_dict
, ni
->nick
);
522 static unreg_func_t
*unreg_func_list
;
523 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
526 reg_unreg_func(unreg_func_t func
)
528 if (unreg_func_used
== unreg_func_size
) {
529 if (unreg_func_size
) {
530 unreg_func_size
<<= 1;
531 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
534 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
537 unreg_func_list
[unreg_func_used
++] = func
;
541 nickserv_free_cookie(void *data
)
543 struct handle_cookie
*cookie
= data
;
544 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
545 if (cookie
->data
) free(cookie
->data
);
550 free_handle_info(void *vhi
)
552 struct handle_info
*hi
= vhi
;
554 #ifdef WITH_PROTOCOL_BAHAMUT
557 inttobase64(id
, hi
->id
, IDLEN
);
558 dict_remove(nickserv_id_dict
, id
);
561 free_string_list(hi
->masks
);
565 delete_nick(hi
->nicks
);
571 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
572 nickserv_free_cookie(hi
->cookie
);
574 if (hi
->email_addr
) {
575 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
576 handle_info_list_remove(hil
, hi
);
578 dict_remove(nickserv_email_dict
, hi
->email_addr
);
583 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
586 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
589 struct userNode
*uNode
;
591 for (n
=0; n
<unreg_func_used
; n
++)
592 unreg_func_list
[n
](notify
, hi
);
594 if (nickserv_conf
.sync_log
) {
595 uNode
= GetUserH(hi
->users
->nick
);
599 set_user_handle_info(hi
->users
, NULL
, 0);
602 if (nickserv_conf
.disable_nicks
)
603 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
605 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
608 if (nickserv_conf
.sync_log
)
609 SyncLog("UNREGISTER %s", hi
->handle
);
611 dict_remove(nickserv_handle_dict
, hi
->handle
);
615 get_handle_info(const char *handle
)
617 return dict_find(nickserv_handle_dict
, handle
, 0);
621 get_nick_info(const char *nick
)
623 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
627 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
632 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
633 mn
= channel
->members
.list
[nn
];
634 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
641 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
642 if (!user
->handle_info
) {
644 send_message(user
, bot
, "MSG_AUTHENTICATE");
648 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
650 send_message(user
, bot
, "NSMSG_NO_ACCESS");
654 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
656 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
660 if (user
->handle_info
->opserv_level
< min_level
) {
662 send_message(user
, bot
, "NSMSG_NO_ACCESS");
670 is_valid_handle(const char *handle
)
672 struct userNode
*user
;
673 /* cant register a juped nick/service nick as handle, to prevent confusion */
674 user
= GetUserH(handle
);
675 if (user
&& IsLocal(user
))
677 /* check against maximum length */
678 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
680 /* for consistency, only allow account names that could be nicks */
681 if (!is_valid_nick(handle
))
683 /* disallow account names that look like bad words */
684 if (opserv_bad_channel(handle
))
686 /* test either regex or containing all valid chars */
687 if (nickserv_conf
.valid_handle_regex_set
) {
688 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
691 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
692 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
696 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
701 is_registerable_nick(const char *nick
)
703 /* make sure it could be used as an account name */
704 if (!is_valid_handle(nick
))
707 if (strlen(nick
) > NICKLEN
)
709 /* test either regex or as valid handle */
710 if (nickserv_conf
.valid_nick_regex_set
) {
711 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
714 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
715 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
721 /* this has been replaced with one in tools.c
724 is_valid_email_addr(const char *email)
726 return strchr(email, '@') != NULL;
732 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
734 if (hi
->email_addr
) {
735 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
736 return hi
->email_addr
;
746 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
748 struct handle_info
*hi
;
749 struct userNode
*target
;
753 if (!(hi
= get_handle_info(++name
))) {
754 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
759 if (!(target
= GetUserH(name
))) {
760 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
763 if (IsLocal(target
)) {
764 if (IsService(target
))
765 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
767 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
770 if (!(hi
= target
->handle_info
)) {
771 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
779 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
780 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
782 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
783 if ((user
->handle_info
->opserv_level
== 1000)
784 || (user
->handle_info
== hi
)
785 || ((user
->handle_info
->opserv_level
== 0)
786 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
787 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
791 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
795 static struct handle_info
*
796 get_victim_oper(struct userNode
*user
, const char *target
)
798 struct handle_info
*hi
;
799 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
801 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
802 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
805 return oper_outranks(user
, hi
) ? hi
: NULL
;
809 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
813 /* If no hostmasks on the account, allow it. */
814 if (!hi
->masks
->used
)
816 /* If any hostmask matches, allow it. */
817 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
818 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
820 /* If they are allowauthed to this account, allow it (removing the aa). */
821 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
822 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
825 /* The user is not allowed to use this account. */
830 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
833 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
837 if (len
< nickserv_conf
.password_min_length
) {
839 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
842 if (!irccasecmp(pass
, handle
)) {
844 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
847 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
850 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
853 for (i
=0; i
<len
; i
++) {
854 if (isdigit(pass
[i
]))
856 if (isupper(pass
[i
]))
858 if (islower(pass
[i
]))
861 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
862 || (cnt_upper
< nickserv_conf
.password_min_upper
)
863 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
865 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
871 static auth_func_t
*auth_func_list
;
872 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
875 reg_auth_func(auth_func_t func
)
877 if (auth_func_used
== auth_func_size
) {
878 if (auth_func_size
) {
879 auth_func_size
<<= 1;
880 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
883 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
886 auth_func_list
[auth_func_used
++] = func
;
889 static handle_rename_func_t
*rf_list
;
890 static unsigned int rf_list_size
, rf_list_used
;
893 reg_handle_rename_func(handle_rename_func_t func
)
895 if (rf_list_used
== rf_list_size
) {
898 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
901 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
904 rf_list
[rf_list_used
++] = func
;
908 generate_fakehost(struct handle_info
*handle
)
910 extern const char *hidden_host_suffix
;
911 static char buffer
[HOSTLEN
+1];
913 if (!handle
->fakehost
) {
914 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
916 } else if (handle
->fakehost
[0] == '.') {
917 /* A leading dot indicates the stored value is actually a title. */
918 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
921 return handle
->fakehost
;
925 apply_fakehost(struct handle_info
*handle
)
927 struct userNode
*target
;
932 fake
= generate_fakehost(handle
);
933 for (target
= handle
->users
; target
; target
= target
->next_authed
)
934 assign_fakehost(target
, fake
, 1);
937 void send_func_list(struct userNode
*user
)
940 struct handle_info
*old_info
;
942 old_info
= user
->handle_info
;
944 for (n
=0; n
<auth_func_used
; n
++)
945 auth_func_list
[n
](user
, old_info
);
949 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
952 struct handle_info
*old_info
;
954 /* This can happen if somebody uses COOKIE while authed, or if
955 * they re-auth to their current handle (which is silly, but users
957 if (user
->handle_info
== hi
)
960 if (user
->handle_info
) {
961 struct userNode
*other
;
964 userList_remove(&curr_helpers
, user
);
966 /* remove from next_authed linked list */
967 if (user
->handle_info
->users
== user
) {
968 user
->handle_info
->users
= user
->next_authed
;
970 for (other
= user
->handle_info
->users
;
971 other
->next_authed
!= user
;
972 other
= other
->next_authed
) ;
973 other
->next_authed
= user
->next_authed
;
975 /* if nobody left on old handle, and they're not an oper, remove !god */
976 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
977 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
978 /* record them as being last seen at this time */
979 user
->handle_info
->lastseen
= now
;
980 /* and record their hostmask */
981 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
983 old_info
= user
->handle_info
;
984 user
->handle_info
= hi
;
985 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
986 HANDLE_CLEAR_FLAG(hi
, HELPING
);
988 if (GetUserH(user
->nick
)) {
989 for (n
=0; n
<auth_func_used
; n
++)
990 auth_func_list
[n
](user
, old_info
);
995 struct nick_info
*ni
;
997 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
998 if (nickserv_conf
.warn_clone_auth
) {
999 struct userNode
*other
;
1000 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1001 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1004 user
->next_authed
= hi
->users
;
1008 userList_append(&curr_helpers
, user
);
1010 if (hi
->fakehost
|| old_info
)
1014 #ifdef WITH_PROTOCOL_BAHAMUT
1015 /* Stamp users with their account ID. */
1017 inttobase64(id
, hi
->id
, IDLEN
);
1018 #elif WITH_PROTOCOL_P10
1019 /* Stamp users with their account name. */
1020 char *id
= hi
->handle
;
1022 const char *id
= "???";
1024 if (!nickserv_conf
.disable_nicks
) {
1025 struct nick_info
*ni
;
1026 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1027 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1028 user
->modes
|= FLAGS_REGNICK
;
1033 StampUser(user
, id
, hi
->registered
);
1036 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1037 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1039 /* We cannot clear the user's account ID, unfortunately. */
1040 user
->next_authed
= NULL
;
1044 static struct handle_info
*
1045 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1047 struct handle_info
*hi
;
1048 struct nick_info
*ni
;
1049 char crypted
[MD5_CRYPT_LENGTH
];
1051 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1052 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1056 if(strlen(handle
) > 15)
1058 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1062 if (!is_secure_password(handle
, passwd
, user
))
1065 cryptpass(passwd
, crypted
);
1066 hi
= register_handle(handle
, crypted
, 0);
1067 hi
->masks
= alloc_string_list(1);
1069 hi
->language
= lang_C
;
1070 hi
->registered
= now
;
1072 hi
->flags
= HI_DEFAULT_FLAGS
;
1073 if (settee
&& !no_auth
)
1074 set_user_handle_info(settee
, hi
, 1);
1077 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1078 else if (nickserv_conf
.disable_nicks
)
1079 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1080 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1081 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1083 register_nick(user
->nick
, hi
);
1084 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1086 if (settee
&& (user
!= settee
))
1087 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1092 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1094 cookie
->hi
->cookie
= cookie
;
1095 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1098 /* Contributed by the great sneep of afternet ;) */
1099 /* Since this gets used in a URL, we want to avoid stuff that confuses
1100 * email clients such as ] and ?. a-z, 0-9 only.
1102 void genpass(char *str
, int len
)
1107 for(i
= 0; i
< len
; i
++)
1111 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1112 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1120 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1122 struct handle_cookie
*cookie
;
1123 char subject
[128], body
[4096], *misc
;
1124 const char *netname
, *fmt
;
1128 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1132 cookie
= calloc(1, sizeof(*cookie
));
1134 cookie
->type
= type
;
1135 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1137 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1138 /* Adding dedicated password gen function for more control -Rubin */
1139 genpass(cookie
->cookie
, 10);
1141 *inttobase64(cookie->cookie, rand(), 5);
1142 *inttobase64(cookie->cookie+5, rand(), 5);
1145 netname
= nickserv_conf
.network_name
;
1148 switch (cookie
->type
) {
1150 hi
->passwd
[0] = 0; /* invalidate password */
1151 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1152 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1153 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1156 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1158 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1160 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1163 case PASSWORD_CHANGE
:
1164 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1165 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1166 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1168 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1170 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1171 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1174 misc
= hi
->email_addr
;
1175 hi
->email_addr
= cookie
->data
;
1176 #ifdef stupid_verify_old_email
1178 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1179 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1180 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1181 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1182 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1183 sendmail(nickserv
, hi
, subject
, body
, 1);
1184 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1185 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1188 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1189 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1190 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1191 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1192 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1193 sendmail(nickserv
, hi
, subject
, body
, 1);
1195 #ifdef stupid_verify_old_email
1198 hi
->email_addr
= misc
;
1201 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1202 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1203 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1204 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1205 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1208 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1212 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1213 nickserv_bake_cookie(cookie
);
1217 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1219 cookie
->hi
->cookie
= NULL
;
1220 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1221 nickserv_free_cookie(cookie
);
1225 nickserv_free_email_addr(void *data
)
1227 handle_info_list_clean(data
);
1232 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1234 struct handle_info_list
*hil
;
1235 /* Remove from old handle_info_list ... */
1236 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1237 handle_info_list_remove(hil
, hi
);
1238 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1239 hi
->email_addr
= NULL
;
1241 /* Add to the new list.. */
1242 if (new_email_addr
) {
1243 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1244 hil
= calloc(1, sizeof(*hil
));
1245 hil
->tag
= strdup(new_email_addr
);
1246 handle_info_list_init(hil
);
1247 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1249 handle_info_list_append(hil
, hi
);
1250 hi
->email_addr
= hil
->tag
;
1254 static NICKSERV_FUNC(cmd_register
)
1256 struct handle_info
*hi
;
1257 const char *email_addr
, *password
;
1258 char syncpass
[MD5_CRYPT_LENGTH
];
1259 int no_auth
, weblink
;
1261 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1262 /* Require the first handle registered to belong to someone +o. */
1263 reply("NSMSG_REQUIRE_OPER");
1267 if (user
->handle_info
) {
1268 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1272 if (IsRegistering(user
)) {
1273 reply("NSMSG_ALREADY_REGISTERING");
1277 if (IsStamped(user
)) {
1278 /* Unauthenticated users might still have been stamped
1279 previously and could therefore have a hidden host;
1280 do not allow them to register a new account. */
1281 reply("NSMSG_STAMPED_REGISTER");
1285 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1287 if (!is_valid_handle(argv
[1])) {
1288 reply("NSMSG_BAD_HANDLE", argv
[1]);
1293 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1294 struct handle_info_list
*hil
;
1297 /* Remember email address. */
1298 email_addr
= argv
[3];
1300 /* Check that the email address looks valid.. */
1301 if (!valid_email(email_addr
)) {
1302 reply("NSMSG_BAD_EMAIL_ADDR");
1306 /* .. and that we are allowed to send to it. */
1307 if ((str
= sendmail_prohibited_address(email_addr
))) {
1308 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1312 /* If we do email verify, make sure we don't spam the address. */
1313 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1315 for (nn
=0; nn
<hil
->used
; nn
++) {
1316 if (hil
->list
[nn
]->cookie
) {
1317 reply("NSMSG_EMAIL_UNACTIVATED");
1321 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1322 reply("NSMSG_EMAIL_OVERUSED");
1335 /* Webregister hack - send URL instead of IRC cookie
1338 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1342 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1344 /* Add any masks they should get. */
1345 if (nickserv_conf
.default_hostmask
) {
1346 string_list_append(hi
->masks
, strdup("*@*"));
1348 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1349 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1350 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1353 /* If they're the first to register, give them level 1000. */
1354 if (dict_size(nickserv_handle_dict
) == 1) {
1355 hi
->opserv_level
= 1000;
1356 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1359 /* Set their email address. */
1361 nickserv_set_email_addr(hi
, email_addr
);
1363 /* If they need to do email verification, tell them. */
1365 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1367 /* Set registering flag.. */
1368 user
->modes
|= FLAGS_REGISTERING
;
1370 if (nickserv_conf
.sync_log
) {
1371 cryptpass(password
, syncpass
);
1373 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1374 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1377 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1380 /* this wont work if email is required .. */
1381 process_adduser_pending(user
);
1386 static NICKSERV_FUNC(cmd_oregister
)
1389 struct userNode
*settee
;
1390 struct handle_info
*hi
;
1392 NICKSERV_MIN_PARMS(nickserv_conf
.email_required
? 5 : 4);
1394 if (!is_valid_handle(argv
[1])) {
1395 reply("NSMSG_BAD_HANDLE", argv
[1]);
1399 if (nickserv_conf
.email_required
) {
1400 if (!valid_email(argv
[4])) {
1401 reply("NSMSG_BAD_EMAIL_ADDR");
1406 if (strchr(argv
[3], '@')) {
1407 mask
= canonicalize_hostmask(strdup(argv
[3]));
1409 settee
= GetUserH(nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1411 reply("MSG_NICK_UNKNOWN", nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1418 } else if ((settee
= GetUserH(argv
[3]))) {
1419 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1421 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1424 if (settee
&& settee
->handle_info
) {
1425 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1429 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1430 if (nickserv_conf
.email_required
) {
1431 nickserv_set_email_addr(hi
, argv
[4]);
1432 if (nickserv_conf
.sync_log
)
1433 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, argv
[4], user
->info
);
1438 string_list_append(hi
->masks
, mask
);
1442 static NICKSERV_FUNC(cmd_handleinfo
)
1445 unsigned int i
, pos
=0, herelen
;
1446 struct userNode
*target
, *next_un
;
1447 struct handle_info
*hi
;
1448 const char *nsmsg_none
;
1451 if (!(hi
= user
->handle_info
)) {
1452 reply("NSMSG_MUST_AUTH");
1455 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1459 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1460 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1462 #ifdef WITH_PROTOCOL_BAHAMUT
1463 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1465 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1468 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1469 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1471 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1474 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1475 if (HANDLE_FLAGGED(hi
, FROZEN
))
1476 reply("NSMSG_HANDLEINFO_VACATION");
1478 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1479 struct do_not_register
*dnr
;
1480 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1481 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1482 if (!oper_outranks(user
, hi
))
1484 } else if (hi
!= user
->handle_info
) {
1485 reply("NSMSG_HANDLEINFO_END");
1489 if (nickserv_conf
.email_enabled
)
1490 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1494 switch (hi
->cookie
->type
) {
1495 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1496 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1497 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1498 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1499 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1505 unsigned long flen
= 1;
1506 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1508 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1509 if (hi
->flags
& 1 << i
)
1510 flags
[flen
++] = handle_flags
[i
];
1512 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1514 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1517 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1518 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1519 || (hi
->opserv_level
> 0)) {
1520 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1523 if (IsHelping(user
) || IsOper(user
))
1528 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1529 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1534 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1536 if (hi
->last_quit_host
[0])
1537 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1539 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1541 if (nickserv_conf
.disable_nicks
) {
1542 /* nicks disabled; don't show anything about registered nicks */
1543 } else if (hi
->nicks
) {
1544 struct nick_info
*ni
, *next_ni
;
1545 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1546 herelen
= strlen(ni
->nick
);
1547 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1549 goto print_nicks_buff
;
1553 memcpy(buff
+pos
, ni
->nick
, herelen
);
1554 pos
+= herelen
; buff
[pos
++] = ' ';
1558 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1563 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1566 if (hi
->masks
->used
) {
1567 for (i
=0; i
< hi
->masks
->used
; i
++) {
1568 herelen
= strlen(hi
->masks
->list
[i
]);
1569 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1571 goto print_mask_buff
;
1573 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1574 pos
+= herelen
; buff
[pos
++] = ' ';
1575 if (i
+1 == hi
->masks
->used
) {
1578 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1583 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1587 struct userData
*channel
, *next
;
1590 for (channel
= hi
->channels
; channel
; channel
= next
) {
1591 next
= channel
->u_next
;
1592 name
= channel
->channel
->channel
->name
;
1593 herelen
= strlen(name
);
1594 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1596 goto print_chans_buff
;
1598 if (IsUserSuspended(channel
))
1600 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1604 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1609 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1612 for (target
= hi
->users
; target
; target
= next_un
) {
1613 herelen
= strlen(target
->nick
);
1614 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1616 goto print_cnick_buff
;
1618 next_un
= target
->next_authed
;
1620 memcpy(buff
+pos
, target
->nick
, herelen
);
1621 pos
+= herelen
; buff
[pos
++] = ' ';
1625 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1630 reply("NSMSG_HANDLEINFO_END");
1634 static NICKSERV_FUNC(cmd_userinfo
)
1636 struct userNode
*target
;
1638 NICKSERV_MIN_PARMS(2);
1639 if (!(target
= GetUserH(argv
[1]))) {
1640 reply("MSG_NICK_UNKNOWN", argv
[1]);
1643 if (target
->handle_info
)
1644 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1646 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1650 static NICKSERV_FUNC(cmd_nickinfo
)
1652 struct nick_info
*ni
;
1654 NICKSERV_MIN_PARMS(2);
1655 if (!(ni
= get_nick_info(argv
[1]))) {
1656 reply("MSG_NICK_UNKNOWN", argv
[1]);
1659 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1663 static NICKSERV_FUNC(cmd_rename_handle
)
1665 struct handle_info
*hi
;
1666 struct userNode
*uNode
;
1667 char msgbuf
[MAXLEN
], *old_handle
;
1670 NICKSERV_MIN_PARMS(3);
1671 if (!(hi
= get_victim_oper(user
, argv
[1])))
1673 if (!is_valid_handle(argv
[2])) {
1674 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1677 if (get_handle_info(argv
[2])) {
1678 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1681 if(strlen(argv
[2]) > 15)
1683 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1687 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1688 hi
->handle
= strdup(argv
[2]);
1689 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1690 for (nn
=0; nn
<rf_list_used
; nn
++)
1691 rf_list
[nn
](hi
, old_handle
);
1692 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1695 if (nickserv_conf
.sync_log
) {
1696 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1697 irc_rename(uNode
, hi
->handle
);
1699 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1702 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1703 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1708 static failpw_func_t
*failpw_func_list
;
1709 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1712 reg_failpw_func(failpw_func_t func
)
1714 if (failpw_func_used
== failpw_func_size
) {
1715 if (failpw_func_size
) {
1716 failpw_func_size
<<= 1;
1717 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1719 failpw_func_size
= 8;
1720 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1723 failpw_func_list
[failpw_func_used
++] = func
;
1727 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1729 * called by nefariouses enhanced AC login-on-connect code
1732 struct handle_info
*loc_auth(char *handle
, char *password
)
1734 int pw_arg
, used
, maxlogins
;
1737 struct handle_info
*hi
;
1738 struct userNode
*other
;
1740 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1746 /* We don't know the users hostname, or anything because they
1747 * havn't registered yet. So we can only allow LOC if your
1748 * account has *@* as a hostmask.
1750 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1752 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1761 /* Responses from here on look up the language used by the handle they asked about. */
1762 if (!checkpass(password
, hi
->passwd
)) {
1765 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1768 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1769 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1770 if (++used
>= maxlogins
) {
1777 static NICKSERV_FUNC(cmd_auth
)
1779 int pw_arg
, used
, maxlogins
;
1780 struct handle_info
*hi
;
1782 struct userNode
*other
;
1784 if (user
->handle_info
) {
1785 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1788 if (IsStamped(user
)) {
1789 /* Unauthenticated users might still have been stamped
1790 previously and could therefore have a hidden host;
1791 do not allow them to authenticate. */
1792 reply("NSMSG_STAMPED_AUTH");
1796 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1798 } else if (argc
== 2) {
1799 if (nickserv_conf
.disable_nicks
) {
1800 if (!(hi
= get_handle_info(user
->nick
))) {
1801 reply("NSMSG_HANDLE_NOT_FOUND");
1805 /* try to look up their handle from their nick */
1806 struct nick_info
*ni
;
1807 ni
= get_nick_info(user
->nick
);
1809 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1816 reply("MSG_MISSING_PARAMS", argv
[0]);
1817 svccmd_send_help_brief(user
, nickserv
, cmd
);
1821 reply("NSMSG_HANDLE_NOT_FOUND");
1824 /* Responses from here on look up the language used by the handle they asked about. */
1825 passwd
= argv
[pw_arg
];
1826 if (!valid_user_for(user
, hi
)) {
1827 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1828 send_message_type(4, user
, cmd
->parent
->bot
,
1829 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1832 send_message_type(4, user
, cmd
->parent
->bot
,
1833 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1835 argv
[pw_arg
] = "BADMASK";
1838 if (!checkpass(passwd
, hi
->passwd
)) {
1840 send_message_type(4, user
, cmd
->parent
->bot
,
1841 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1842 argv
[pw_arg
] = "BADPASS";
1843 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1844 if (nickserv_conf
.autogag_enabled
) {
1845 if (!user
->auth_policer
.params
) {
1846 user
->auth_policer
.last_req
= now
;
1847 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1849 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1851 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1852 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1853 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1855 argv
[pw_arg
] = "GAGGED";
1860 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1861 send_message_type(4, user
, cmd
->parent
->bot
,
1862 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1863 argv
[pw_arg
] = "SUSPENDED";
1866 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1867 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1868 if (++used
>= maxlogins
) {
1869 send_message_type(4, user
, cmd
->parent
->bot
,
1870 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1872 argv
[pw_arg
] = "MAXLOGINS";
1877 set_user_handle_info(user
, hi
, 1);
1878 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1879 reply("NSMSG_PLEASE_SET_EMAIL");
1880 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1881 reply("NSMSG_WEAK_PASSWORD");
1882 if (hi
->passwd
[0] != '$')
1883 cryptpass(passwd
, hi
->passwd
);
1885 /* If a channel was waiting for this user to auth,
1886 * finish adding them */
1887 process_adduser_pending(user
);
1889 reply("NSMSG_AUTH_SUCCESS");
1892 /* Set +x if autohide is on */
1893 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
1894 irc_umode(user
, "+x");
1896 if(!IsOper(user
)) /* If they arnt already opered.. */
1898 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
1899 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
1901 irc_umode(user
,nickserv_conf
.auto_admin
);
1902 reply("NSMSG_AUTO_OPER_ADMIN");
1904 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
1906 irc_umode(user
,nickserv_conf
.auto_oper
);
1907 reply("NSMSG_AUTO_OPER");
1911 /* Wipe out the pass for the logs */
1912 argv
[pw_arg
] = "****";
1916 static allowauth_func_t
*allowauth_func_list
;
1917 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1920 reg_allowauth_func(allowauth_func_t func
)
1922 if (allowauth_func_used
== allowauth_func_size
) {
1923 if (allowauth_func_size
) {
1924 allowauth_func_size
<<= 1;
1925 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1927 allowauth_func_size
= 8;
1928 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1931 allowauth_func_list
[allowauth_func_used
++] = func
;
1934 static NICKSERV_FUNC(cmd_allowauth
)
1936 struct userNode
*target
;
1937 struct handle_info
*hi
;
1940 NICKSERV_MIN_PARMS(2);
1941 if (!(target
= GetUserH(argv
[1]))) {
1942 reply("MSG_NICK_UNKNOWN", argv
[1]);
1945 if (target
->handle_info
) {
1946 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1949 if (IsStamped(target
)) {
1950 /* Unauthenticated users might still have been stamped
1951 previously and could therefore have a hidden host;
1952 do not allow them to authenticate to an account. */
1953 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1958 else if (!(hi
= get_handle_info(argv
[2]))) {
1959 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1963 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1964 reply("MSG_USER_OUTRANKED", hi
->handle
);
1967 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1968 || (hi
->opserv_level
> 0))
1969 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1970 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1973 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1974 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1975 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1976 if (nickserv_conf
.email_enabled
)
1977 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1979 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1980 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1982 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1984 for (n
=0; n
<allowauth_func_used
; n
++)
1985 allowauth_func_list
[n
](user
, target
, hi
);
1989 static NICKSERV_FUNC(cmd_authcookie
)
1991 struct handle_info
*hi
;
1993 NICKSERV_MIN_PARMS(2);
1994 if (user
->handle_info
) {
1995 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1998 if (IsStamped(user
)) {
1999 /* Unauthenticated users might still have been stamped
2000 previously and could therefore have a hidden host;
2001 do not allow them to authenticate to an account. */
2002 reply("NSMSG_STAMPED_AUTHCOOKIE");
2005 if (!(hi
= get_handle_info(argv
[1]))) {
2006 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2009 if (!hi
->email_addr
) {
2010 reply("MSG_SET_EMAIL_ADDR");
2013 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2017 static NICKSERV_FUNC(cmd_delcookie
)
2019 struct handle_info
*hi
;
2021 hi
= user
->handle_info
;
2023 reply("NSMSG_NO_COOKIE");
2026 switch (hi
->cookie
->type
) {
2029 reply("NSMSG_MUST_TIME_OUT");
2032 nickserv_eat_cookie(hi
->cookie
);
2033 reply("NSMSG_ATE_COOKIE");
2039 static NICKSERV_FUNC(cmd_odelcookie
)
2041 struct handle_info
*hi
;
2043 NICKSERV_MIN_PARMS(2);
2045 if (!(hi
= get_victim_oper(user
, argv
[1])))
2049 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2053 nickserv_eat_cookie(hi
->cookie
);
2054 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2059 static NICKSERV_FUNC(cmd_resetpass
)
2061 struct handle_info
*hi
;
2062 char crypted
[MD5_CRYPT_LENGTH
];
2065 NICKSERV_MIN_PARMS(3);
2066 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2070 if (user
->handle_info
) {
2071 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2074 if (IsStamped(user
)) {
2075 /* Unauthenticated users might still have been stamped
2076 previously and could therefore have a hidden host;
2077 do not allow them to activate an account. */
2078 reply("NSMSG_STAMPED_RESETPASS");
2081 if (!(hi
= get_handle_info(argv
[1]))) {
2082 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2085 if (!hi
->email_addr
) {
2086 reply("MSG_SET_EMAIL_ADDR");
2089 cryptpass(argv
[2], crypted
);
2091 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2095 static NICKSERV_FUNC(cmd_cookie
)
2097 struct handle_info
*hi
;
2100 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2103 NICKSERV_MIN_PARMS(3);
2104 if (!(hi
= get_handle_info(argv
[1]))) {
2105 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2111 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2112 reply("NSMSG_HANDLE_SUSPENDED");
2117 reply("NSMSG_NO_COOKIE");
2121 /* Check validity of operation before comparing cookie to
2122 * prohibit guessing by authed users. */
2123 if (user
->handle_info
2124 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2125 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2126 reply("NSMSG_CANNOT_COOKIE");
2130 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2131 reply("NSMSG_BAD_COOKIE");
2135 switch (hi
->cookie
->type
) {
2137 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2138 set_user_handle_info(user
, hi
, 1);
2139 reply("NSMSG_HANDLE_ACTIVATED");
2140 if (nickserv_conf
.sync_log
)
2141 SyncLog("ACCOUNTACC %s", hi
->handle
);
2143 case PASSWORD_CHANGE
:
2144 set_user_handle_info(user
, hi
, 1);
2145 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2146 reply("NSMSG_PASSWORD_CHANGED");
2147 if (nickserv_conf
.sync_log
)
2148 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2151 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2153 * This should only happen if an OREGISTER was sent. Require
2154 * email must be enabled! - SiRVulcaN
2156 if (nickserv_conf
.sync_log
)
2157 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2159 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2160 reply("NSMSG_EMAIL_CHANGED");
2161 if (nickserv_conf
.sync_log
)
2162 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2165 set_user_handle_info(user
, hi
, 1);
2166 reply("NSMSG_AUTH_SUCCESS");
2169 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2170 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2174 nickserv_eat_cookie(hi
->cookie
);
2176 process_adduser_pending(user
);
2181 static NICKSERV_FUNC(cmd_oregnick
) {
2183 struct handle_info
*target
;
2184 struct nick_info
*ni
;
2186 NICKSERV_MIN_PARMS(3);
2187 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2190 if (!is_registerable_nick(nick
)) {
2191 reply("NSMSG_BAD_NICK", nick
);
2194 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2196 reply("NSMSG_NICK_EXISTS", nick
);
2199 register_nick(nick
, target
);
2200 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2204 static NICKSERV_FUNC(cmd_regnick
) {
2206 struct nick_info
*ni
;
2208 if (!is_registerable_nick(user
->nick
)) {
2209 reply("NSMSG_BAD_NICK", user
->nick
);
2212 /* count their nicks, see if it's too many */
2213 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2214 if (n
>= nickserv_conf
.nicks_per_handle
) {
2215 reply("NSMSG_TOO_MANY_NICKS");
2218 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2220 reply("NSMSG_NICK_EXISTS", user
->nick
);
2223 register_nick(user
->nick
, user
->handle_info
);
2224 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2228 static NICKSERV_FUNC(cmd_pass
)
2230 struct handle_info
*hi
;
2231 const char *old_pass
, *new_pass
;
2233 NICKSERV_MIN_PARMS(3);
2234 hi
= user
->handle_info
;
2238 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2239 if (!checkpass(old_pass
, hi
->passwd
)) {
2240 argv
[1] = "BADPASS";
2241 reply("NSMSG_PASSWORD_INVALID");
2244 cryptpass(new_pass
, hi
->passwd
);
2245 if (nickserv_conf
.sync_log
)
2246 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2248 reply("NSMSG_PASS_SUCCESS");
2253 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2256 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2257 for (i
=0; i
<hi
->masks
->used
; i
++) {
2258 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2259 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2264 string_list_append(hi
->masks
, new_mask
);
2265 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2269 static NICKSERV_FUNC(cmd_addmask
)
2272 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2273 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2277 if (!is_gline(argv
[1])) {
2278 reply("NSMSG_MASK_INVALID", argv
[1]);
2281 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2285 static NICKSERV_FUNC(cmd_oaddmask
)
2287 struct handle_info
*hi
;
2289 NICKSERV_MIN_PARMS(3);
2290 if (!(hi
= get_victim_oper(user
, argv
[1])))
2292 return nickserv_addmask(user
, hi
, argv
[2]);
2296 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2299 for (i
=0; i
<hi
->masks
->used
; i
++) {
2300 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2301 char *old_mask
= hi
->masks
->list
[i
];
2302 if (hi
->masks
->used
== 1) {
2303 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2306 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2307 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2312 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2316 static NICKSERV_FUNC(cmd_delmask
)
2318 NICKSERV_MIN_PARMS(2);
2319 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2322 static NICKSERV_FUNC(cmd_odelmask
)
2324 struct handle_info
*hi
;
2325 NICKSERV_MIN_PARMS(3);
2326 if (!(hi
= get_victim_oper(user
, argv
[1])))
2328 return nickserv_delmask(user
, hi
, argv
[2]);
2332 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2333 unsigned int nn
, add
= 1, pos
;
2334 unsigned long added
, removed
, flag
;
2336 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2338 case '+': add
= 1; break;
2339 case '-': add
= 0; break;
2341 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2342 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2345 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2346 /* cheesy avoidance of looking up the flag name.. */
2347 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2350 flag
= 1 << (pos
- 1);
2352 added
|= flag
, removed
&= ~flag
;
2354 removed
|= flag
, added
&= ~flag
;
2359 *premoved
= removed
;
2364 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2366 unsigned long before
, after
, added
, removed
;
2367 struct userNode
*uNode
;
2369 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2370 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2372 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2373 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2375 /* Strip helping flag if they're only a support helper and not
2376 * currently in #support. */
2377 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2378 struct channelList
*schannels
;
2380 schannels
= chanserv_support_channels();
2381 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2382 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2383 if (GetUserMode(schannels
->list
[ii
], uNode
))
2385 if (ii
< schannels
->used
)
2389 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2392 if (after
&& !before
) {
2393 /* Add user to current helper list. */
2394 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2395 userList_append(&curr_helpers
, uNode
);
2396 } else if (!after
&& before
) {
2397 /* Remove user from current helper list. */
2398 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2399 userList_remove(&curr_helpers
, uNode
);
2406 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2410 char *set_display
[] = {
2411 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", /* "STYLE", */
2412 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2413 "FAKEHOST", "TITLE", "EPITHET"
2416 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2417 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2419 /* Do this so options are presented in a consistent order. */
2420 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2421 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2422 opt(user
, hi
, override
, 0, NULL
);
2423 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2426 static NICKSERV_FUNC(cmd_set
)
2428 struct handle_info
*hi
;
2431 hi
= user
->handle_info
;
2433 set_list(user
, hi
, 0);
2436 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2437 reply("NSMSG_INVALID_OPTION", argv
[1]);
2440 return opt(user
, hi
, 0, argc
-1, argv
+1);
2443 static NICKSERV_FUNC(cmd_oset
)
2445 struct handle_info
*hi
;
2448 NICKSERV_MIN_PARMS(2);
2450 if (!(hi
= get_victim_oper(user
, argv
[1])))
2454 set_list(user
, hi
, 0);
2458 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2459 reply("NSMSG_INVALID_OPTION", argv
[2]);
2463 return opt(user
, hi
, 1, argc
-2, argv
+2);
2466 static OPTION_FUNC(opt_info
)
2470 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2472 hi
->infoline
= NULL
;
2474 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2478 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2479 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2483 static OPTION_FUNC(opt_width
)
2486 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2488 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2489 hi
->screen_width
= MIN_LINE_SIZE
;
2490 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2491 hi
->screen_width
= MAX_LINE_SIZE
;
2493 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2497 static OPTION_FUNC(opt_tablewidth
)
2500 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2502 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2503 hi
->table_width
= MIN_LINE_SIZE
;
2504 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2505 hi
->table_width
= MAX_LINE_SIZE
;
2507 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2511 static OPTION_FUNC(opt_color
)
2514 if (enabled_string(argv
[1]))
2515 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2516 else if (disabled_string(argv
[1]))
2517 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2519 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2524 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2528 static OPTION_FUNC(opt_privmsg
)
2531 if (enabled_string(argv
[1]))
2532 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2533 else if (disabled_string(argv
[1]))
2534 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2536 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2541 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2545 static OPTION_FUNC(opt_autohide
)
2548 if (enabled_string(argv
[1]))
2549 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2550 else if (disabled_string(argv
[1]))
2551 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2553 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2558 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2563 static OPTION_FUNC(opt_style)
2568 if (!irccasecmp(argv[1], "Zoot"))
2569 hi->userlist_style = HI_STYLE_ZOOT;
2570 else if (!irccasecmp(argv[1], "def"))
2571 hi->userlist_style = HI_STYLE_DEF;
2574 switch (hi->userlist_style) {
2583 send_message(user, nickserv, "NSMSG_SET_STYLE", style);
2588 static OPTION_FUNC(opt_announcements
)
2593 if (enabled_string(argv
[1]))
2594 hi
->announcements
= 'y';
2595 else if (disabled_string(argv
[1]))
2596 hi
->announcements
= 'n';
2597 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2598 hi
->announcements
= '?';
2600 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2605 switch (hi
->announcements
) {
2606 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2607 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2608 case '?': choice
= "default"; break;
2609 default: choice
= "unknown"; break;
2611 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2615 static OPTION_FUNC(opt_password
)
2618 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2623 cryptpass(argv
[1], hi
->passwd
);
2625 if (nickserv_conf
.sync_log
)
2626 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2628 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2632 static OPTION_FUNC(opt_flags
)
2635 unsigned int ii
, flen
;
2638 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2643 nickserv_apply_flags(user
, hi
, argv
[1]);
2645 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2646 if (hi
->flags
& (1 << ii
))
2647 flags
[flen
++] = handle_flags
[ii
];
2650 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2652 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2656 static OPTION_FUNC(opt_email
)
2660 if (!valid_email(argv
[1])) {
2661 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2664 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2665 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2668 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2669 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2671 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2673 nickserv_set_email_addr(hi
, argv
[1]);
2675 nickserv_eat_cookie(hi
->cookie
);
2676 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2679 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2683 static OPTION_FUNC(opt_maxlogins
)
2685 unsigned char maxlogins
;
2687 maxlogins
= strtoul(argv
[1], NULL
, 0);
2688 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2689 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2692 hi
->maxlogins
= maxlogins
;
2694 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2695 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2699 static OPTION_FUNC(opt_language
)
2701 struct language
*lang
;
2703 lang
= language_find(argv
[1]);
2704 if (irccasecmp(lang
->name
, argv
[1]))
2705 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2706 hi
->language
= lang
;
2708 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2713 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2714 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2716 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2717 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2718 && (user
->handle_info
->opserv_level
< 1000))) {
2719 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2722 if ((user
->handle_info
->opserv_level
< new_level
)
2723 || ((user
->handle_info
->opserv_level
== new_level
)
2724 && (user
->handle_info
->opserv_level
< 1000))) {
2725 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2728 if (user
->handle_info
== target
) {
2729 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2732 if (target
->opserv_level
== new_level
)
2734 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2735 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2736 target
->opserv_level
= new_level
;
2740 static OPTION_FUNC(opt_level
)
2745 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2749 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2750 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2754 static OPTION_FUNC(opt_epithet
)
2756 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2759 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2763 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2767 if ((epithet
[0] == '*') && !epithet
[1])
2770 hi
->epithet
= strdup(epithet
);
2774 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2776 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2780 static OPTION_FUNC(opt_title
)
2784 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2786 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2791 if (strchr(title
, '.')) {
2792 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2795 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2796 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2797 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2802 if (!strcmp(title
, "*")) {
2803 hi
->fakehost
= NULL
;
2805 hi
->fakehost
= malloc(strlen(title
)+2);
2806 hi
->fakehost
[0] = '.';
2807 strcpy(hi
->fakehost
+1, title
);
2810 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2811 title
= hi
->fakehost
+ 1;
2815 title
= user_find_message(user
, "MSG_NONE");
2816 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2820 static OPTION_FUNC(opt_fakehost
)
2824 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2826 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2831 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2832 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2836 if (!strcmp(fake
, "*"))
2837 hi
->fakehost
= NULL
;
2839 hi
->fakehost
= strdup(fake
);
2840 fake
= hi
->fakehost
;
2843 fake
= generate_fakehost(hi
);
2845 fake
= user_find_message(user
, "MSG_NONE");
2846 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2850 static OPTION_FUNC(opt_note
)
2853 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2858 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
2863 if ((text
[0] == '*') && !text
[1])
2866 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
2871 send_message(user
, nickserv
, "NSMSG_SET_NOTE", hi
->note
->note
);
2875 static NICKSERV_FUNC(cmd_reclaim
)
2877 struct handle_info
*hi
;
2878 struct nick_info
*ni
;
2879 struct userNode
*victim
;
2881 NICKSERV_MIN_PARMS(2);
2882 hi
= user
->handle_info
;
2883 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2885 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2888 if (ni
->owner
!= user
->handle_info
) {
2889 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2892 victim
= GetUserH(ni
->nick
);
2894 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2897 if (victim
== user
) {
2898 reply("NSMSG_NICK_USER_YOU");
2901 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2902 switch (nickserv_conf
.reclaim_action
) {
2903 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2904 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2905 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2906 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2911 static NICKSERV_FUNC(cmd_unregnick
)
2914 struct handle_info
*hi
;
2915 struct nick_info
*ni
;
2917 hi
= user
->handle_info
;
2918 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2919 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2921 reply("NSMSG_UNKNOWN_NICK", nick
);
2924 if (hi
!= ni
->owner
) {
2925 reply("NSMSG_NOT_YOUR_NICK", nick
);
2928 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2933 static NICKSERV_FUNC(cmd_ounregnick
)
2935 struct nick_info
*ni
;
2937 NICKSERV_MIN_PARMS(2);
2938 if (!(ni
= get_nick_info(argv
[1]))) {
2939 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2942 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2943 reply("MSG_USER_OUTRANKED", ni
->nick
);
2946 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2951 static NICKSERV_FUNC(cmd_unregister
)
2953 struct handle_info
*hi
;
2956 NICKSERV_MIN_PARMS(2);
2957 hi
= user
->handle_info
;
2960 if (checkpass(passwd
, hi
->passwd
)) {
2961 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2964 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2965 reply("NSMSG_PASSWORD_INVALID");
2970 static NICKSERV_FUNC(cmd_ounregister
)
2972 struct handle_info
*hi
;
2974 NICKSERV_MIN_PARMS(2);
2975 if (!(hi
= get_victim_oper(user
, argv
[1])))
2977 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2981 static NICKSERV_FUNC(cmd_status
)
2983 if (nickserv_conf
.disable_nicks
) {
2984 reply("NSMSG_GLOBAL_STATS_NONICK",
2985 dict_size(nickserv_handle_dict
));
2987 if (user
->handle_info
) {
2989 struct nick_info
*ni
;
2990 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2991 reply("NSMSG_HANDLE_STATS", cnt
);
2993 reply("NSMSG_HANDLE_NONE");
2995 reply("NSMSG_GLOBAL_STATS",
2996 dict_size(nickserv_handle_dict
),
2997 dict_size(nickserv_nick_dict
));
3002 static NICKSERV_FUNC(cmd_ghost
)
3004 struct userNode
*target
;
3005 char reason
[MAXLEN
];
3007 NICKSERV_MIN_PARMS(2);
3008 if (!(target
= GetUserH(argv
[1]))) {
3009 reply("MSG_NICK_UNKNOWN", argv
[1]);
3012 if (target
== user
) {
3013 reply("NSMSG_CANNOT_GHOST_SELF");
3016 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3017 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3020 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3021 DelUser(target
, nickserv
, 1, reason
);
3022 reply("NSMSG_GHOST_KILLED", argv
[1]);
3026 static NICKSERV_FUNC(cmd_vacation
)
3028 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3029 reply("NSMSG_ON_VACATION");
3034 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3036 struct handle_info
*hi
;
3039 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3041 #ifdef WITH_PROTOCOL_BAHAMUT
3044 saxdb_start_record(ctx
, iter_key(it
), 0);
3045 if (hi
->announcements
!= '?') {
3046 flags
[0] = hi
->announcements
;
3048 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3051 struct handle_cookie
*cookie
= hi
->cookie
;
3054 switch (cookie
->type
) {
3055 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3056 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3057 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3058 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3059 default: type
= NULL
; break;
3062 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3063 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3064 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3066 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3067 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3068 saxdb_end_record(ctx
);
3072 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3074 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3076 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3077 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3078 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3079 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3080 saxdb_end_record(ctx
);
3084 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3088 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3089 if (hi
->flags
& (1 << ii
))
3090 flags
[flen
++] = handle_flags
[ii
];
3092 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3094 #ifdef WITH_PROTOCOL_BAHAMUT
3095 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3098 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3099 if (hi
->last_quit_host
[0])
3100 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3101 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3102 if (hi
->masks
->used
)
3103 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3105 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3107 struct string_list
*slist
;
3108 struct nick_info
*ni
;
3110 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3111 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3112 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3116 if (hi
->opserv_level
)
3117 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3118 if (hi
->language
!= lang_C
)
3119 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3120 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3121 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3122 if (hi
->screen_width
)
3123 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3124 if (hi
->table_width
)
3125 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3126 flags
[0] = hi
->userlist_style
;
3128 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3129 saxdb_end_record(ctx
);
3134 static handle_merge_func_t
*handle_merge_func_list
;
3135 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3138 reg_handle_merge_func(handle_merge_func_t func
)
3140 if (handle_merge_func_used
== handle_merge_func_size
) {
3141 if (handle_merge_func_size
) {
3142 handle_merge_func_size
<<= 1;
3143 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3145 handle_merge_func_size
= 8;
3146 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3149 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3152 static NICKSERV_FUNC(cmd_merge
)
3154 struct handle_info
*hi_from
, *hi_to
;
3155 struct userNode
*last_user
;
3156 struct userData
*cList
, *cListNext
;
3157 unsigned int ii
, jj
, n
;
3158 char buffer
[MAXLEN
];
3160 NICKSERV_MIN_PARMS(3);
3162 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3164 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3166 if (hi_to
== hi_from
) {
3167 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3171 for (n
=0; n
<handle_merge_func_used
; n
++)
3172 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3174 /* Append "from" handle's nicks to "to" handle's nick list. */
3176 struct nick_info
*last_ni
;
3177 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3178 last_ni
->next
= hi_from
->nicks
;
3180 while (hi_from
->nicks
) {
3181 hi_from
->nicks
->owner
= hi_to
;
3182 hi_from
->nicks
= hi_from
->nicks
->next
;
3185 /* Merge the hostmasks. */
3186 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3187 char *mask
= hi_from
->masks
->list
[ii
];
3188 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3189 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3191 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3192 string_list_append(hi_to
->masks
, strdup(mask
));
3195 /* Merge the lists of authed users. */
3197 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3198 last_user
->next_authed
= hi_from
->users
;
3200 hi_to
->users
= hi_from
->users
;
3202 /* Repoint the old "from" handle's users. */
3203 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3204 last_user
->handle_info
= hi_to
;
3206 hi_from
->users
= NULL
;
3208 /* Merge channel userlists. */
3209 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3210 struct userData
*cList2
;
3211 cListNext
= cList
->u_next
;
3212 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3213 if (cList
->channel
== cList2
->channel
)
3215 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3216 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
);
3217 /* keep cList2 in hi_to; remove cList from hi_from */
3218 del_channel_user(cList
, 1);
3221 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
);
3222 /* remove the lower-ranking cList2 from hi_to */
3223 del_channel_user(cList2
, 1);
3225 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3227 /* cList needs to be moved from hi_from to hi_to */
3228 cList
->handle
= hi_to
;
3229 /* Remove from linked list for hi_from */
3230 assert(!cList
->u_prev
);
3231 hi_from
->channels
= cList
->u_next
;
3233 cList
->u_next
->u_prev
= cList
->u_prev
;
3234 /* Add to linked list for hi_to */
3235 cList
->u_prev
= NULL
;
3236 cList
->u_next
= hi_to
->channels
;
3237 if (hi_to
->channels
)
3238 hi_to
->channels
->u_prev
= cList
;
3239 hi_to
->channels
= cList
;
3243 /* Do they get an OpServ level promotion? */
3244 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3245 hi_to
->opserv_level
= hi_from
->opserv_level
;
3247 /* What about last seen time? */
3248 if (hi_from
->lastseen
> hi_to
->lastseen
)
3249 hi_to
->lastseen
= hi_from
->lastseen
;
3251 /* Does a fakehost carry over? (This intentionally doesn't set it
3252 * for users previously attached to hi_to. They'll just have to
3255 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3256 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3258 /* Notify of success. */
3259 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3260 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3261 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3263 /* Unregister the "from" handle. */
3264 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3269 struct nickserv_discrim
{
3270 unsigned int limit
, min_level
, max_level
;
3271 unsigned long flags_on
, flags_off
;
3272 time_t min_registered
, max_registered
;
3274 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3275 const char *nickmask
;
3276 const char *hostmask
;
3277 const char *handlemask
;
3278 const char *emailmask
;
3281 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3283 struct discrim_apply_info
{
3284 struct nickserv_discrim
*discrim
;
3285 discrim_search_func func
;
3286 struct userNode
*source
;
3287 unsigned int matched
;
3290 static struct nickserv_discrim
*
3291 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3294 struct nickserv_discrim
*discrim
;
3296 discrim
= malloc(sizeof(*discrim
));
3297 memset(discrim
, 0, sizeof(*discrim
));
3298 discrim
->min_level
= 0;
3299 discrim
->max_level
= ~0;
3300 discrim
->limit
= 50;
3301 discrim
->min_registered
= 0;
3302 discrim
->max_registered
= INT_MAX
;
3303 discrim
->lastseen
= now
;
3305 for (i
=0; i
<argc
; i
++) {
3306 if (i
== argc
- 1) {
3307 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3310 if (!irccasecmp(argv
[i
], "limit")) {
3311 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3312 } else if (!irccasecmp(argv
[i
], "flags")) {
3313 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3314 } else if (!irccasecmp(argv
[i
], "registered")) {
3315 const char *cmp
= argv
[++i
];
3316 if (cmp
[0] == '<') {
3317 if (cmp
[1] == '=') {
3318 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3320 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3322 } else if (cmp
[0] == '=') {
3323 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3324 } else if (cmp
[0] == '>') {
3325 if (cmp
[1] == '=') {
3326 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3328 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3331 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3333 } else if (!irccasecmp(argv
[i
], "seen")) {
3334 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3335 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3336 discrim
->nickmask
= argv
[++i
];
3337 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3339 if (!irccasecmp(argv
[i
], "exact")) {
3340 if (i
== argc
- 1) {
3341 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3344 discrim
->hostmask_type
= EXACT
;
3345 } else if (!irccasecmp(argv
[i
], "subset")) {
3346 if (i
== argc
- 1) {
3347 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3350 discrim
->hostmask_type
= SUBSET
;
3351 } else if (!irccasecmp(argv
[i
], "superset")) {
3352 if (i
== argc
- 1) {
3353 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3356 discrim
->hostmask_type
= SUPERSET
;
3357 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3358 if (i
== argc
- 1) {
3359 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3362 discrim
->hostmask_type
= LASTQUIT
;
3365 discrim
->hostmask_type
= SUPERSET
;
3367 discrim
->hostmask
= argv
[++i
];
3368 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3369 if (!irccasecmp(argv
[++i
], "*")) {
3370 discrim
->handlemask
= 0;
3372 discrim
->handlemask
= argv
[i
];
3374 } else if (!irccasecmp(argv
[i
], "email")) {
3375 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3376 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3378 } else if (!irccasecmp(argv
[++i
], "*")) {
3379 discrim
->emailmask
= 0;
3381 discrim
->emailmask
= argv
[i
];
3383 } else if (!irccasecmp(argv
[i
], "access")) {
3384 const char *cmp
= argv
[++i
];
3385 if (cmp
[0] == '<') {
3386 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3387 if (cmp
[1] == '=') {
3388 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3390 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3392 } else if (cmp
[0] == '=') {
3393 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3394 } else if (cmp
[0] == '>') {
3395 if (cmp
[1] == '=') {
3396 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3398 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3401 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3404 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3415 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3417 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3418 || (discrim
->flags_off
& hi
->flags
)
3419 || (discrim
->min_registered
> hi
->registered
)
3420 || (discrim
->max_registered
< hi
->registered
)
3421 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3422 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3423 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3424 || (discrim
->min_level
> hi
->opserv_level
)
3425 || (discrim
->max_level
< hi
->opserv_level
)) {
3428 if (discrim
->hostmask
) {
3430 for (i
=0; i
<hi
->masks
->used
; i
++) {
3431 const char *mask
= hi
->masks
->list
[i
];
3432 if ((discrim
->hostmask_type
== SUBSET
)
3433 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3434 else if ((discrim
->hostmask_type
== EXACT
)
3435 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3436 else if ((discrim
->hostmask_type
== SUPERSET
)
3437 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3438 else if ((discrim
->hostmask_type
== LASTQUIT
)
3439 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3441 if (i
==hi
->masks
->used
) return 0;
3443 if (discrim
->nickmask
) {
3444 struct nick_info
*nick
= hi
->nicks
;
3446 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3449 if (!nick
) return 0;
3455 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3457 dict_iterator_t it
, next
;
3458 unsigned int matched
;
3460 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3461 it
&& (matched
< discrim
->limit
);
3463 next
= iter_next(it
);
3464 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3465 dsf(source
, iter_data(it
));
3473 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3475 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3479 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3484 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3486 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3487 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3491 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3493 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3494 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3495 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3496 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3497 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3501 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3503 struct handle_info_list hil
;
3504 struct helpfile_table tbl
;
3509 memset(&hil
, 0, sizeof(hil
));
3510 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3511 struct handle_info
*hi
= iter_data(it
);
3512 if (hi
->opserv_level
)
3513 handle_info_list_append(&hil
, hi
);
3515 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3516 tbl
.length
= hil
.used
+ 1;
3518 tbl
.flags
= TABLE_NO_FREE
;
3519 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3520 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3523 for (ii
= 0; ii
< hil
.used
; ) {
3524 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3525 ary
[0] = hil
.list
[ii
]->handle
;
3526 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3527 tbl
.contents
[++ii
] = ary
;
3529 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3530 reply("MSG_MATCH_COUNT", hil
.used
);
3531 for (ii
= 0; ii
< hil
.used
; ii
++)
3532 free(tbl
.contents
[ii
]);
3537 static NICKSERV_FUNC(cmd_search
)
3539 struct nickserv_discrim
*discrim
;
3540 discrim_search_func action
;
3541 struct svccmd
*subcmd
;
3542 unsigned int matches
;
3545 NICKSERV_MIN_PARMS(3);
3546 sprintf(buf
, "search %s", argv
[1]);
3547 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3548 if (!irccasecmp(argv
[1], "print"))
3549 action
= search_print_func
;
3550 else if (!irccasecmp(argv
[1], "count"))
3551 action
= search_count_func
;
3552 else if (!irccasecmp(argv
[1], "unregister"))
3553 action
= search_unregister_func
;
3555 reply("NSMSG_INVALID_ACTION", argv
[1]);
3559 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3562 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3566 if (action
== search_print_func
)
3567 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3568 else if (action
== search_count_func
)
3569 discrim
->limit
= INT_MAX
;
3571 matches
= nickserv_discrim_search(discrim
, action
, user
);
3574 reply("MSG_MATCH_COUNT", matches
);
3576 reply("MSG_NO_MATCHES");
3582 static MODCMD_FUNC(cmd_checkpass
)
3584 struct handle_info
*hi
;
3586 NICKSERV_MIN_PARMS(3);
3587 if (!(hi
= get_handle_info(argv
[1]))) {
3588 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3591 if (checkpass(argv
[2], hi
->passwd
))
3592 reply("CHECKPASS_YES");
3594 reply("CHECKPASS_NO");
3600 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3603 struct string_list
*masks
, *slist
;
3604 struct handle_info
*hi
;
3605 struct userNode
*authed_users
;
3606 struct userData
*channels
;
3607 unsigned long int id
;
3610 char *setter
, *note
;
3613 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3614 id
= str
? strtoul(str
, NULL
, 0) : 0;
3615 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3617 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3620 if ((hi
= get_handle_info(handle
))) {
3621 authed_users
= hi
->users
;
3622 channels
= hi
->channels
;
3624 hi
->channels
= NULL
;
3625 dict_remove(nickserv_handle_dict
, hi
->handle
);
3627 authed_users
= NULL
;
3630 hi
= register_handle(handle
, str
, id
);
3632 hi
->users
= authed_users
;
3633 while (authed_users
) {
3634 authed_users
->handle_info
= hi
;
3635 authed_users
= authed_users
->next_authed
;
3638 hi
->channels
= channels
;
3639 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3640 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3641 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3642 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3643 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3644 hi
->language
= language_find(str
? str
: "C");
3645 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3646 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3647 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3649 hi
->infoline
= strdup(str
);
3650 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3651 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3652 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3653 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3654 /* We want to read the nicks even if disable_nicks is set. This is so
3655 * that we don't lose the nick data entirely. */
3656 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3658 for (ii
=0; ii
<slist
->used
; ii
++)
3659 register_nick(slist
->list
[ii
], hi
);
3661 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3663 for (ii
=0; str
[ii
]; ii
++)
3664 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3666 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3667 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3668 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3669 hi
->announcements
= str
? str
[0] : '?';
3670 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3671 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3672 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3673 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3674 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3676 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3678 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3679 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3681 nickserv_set_email_addr(hi
, str
);
3682 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3684 hi
->epithet
= strdup(str
);
3685 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3687 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3688 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3689 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3690 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3691 if (setter
&& date
&& note
)
3693 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3698 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3700 hi
->fakehost
= strdup(str
);
3701 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3703 const char *data
, *type
, *expires
, *cookie_str
;
3704 struct handle_cookie
*cookie
;
3706 cookie
= calloc(1, sizeof(*cookie
));
3707 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3708 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3709 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3710 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3711 if (!type
|| !expires
|| !cookie_str
) {
3712 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3715 if (!irccasecmp(type
, KEY_ACTIVATION
))
3716 cookie
->type
= ACTIVATION
;
3717 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3718 cookie
->type
= PASSWORD_CHANGE
;
3719 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3720 cookie
->type
= EMAIL_CHANGE
;
3721 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3722 cookie
->type
= ALLOWAUTH
;
3724 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3727 cookie
->expires
= strtoul(expires
, NULL
, 0);
3728 if (cookie
->expires
< now
)
3731 cookie
->data
= strdup(data
);
3732 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3736 nickserv_bake_cookie(cookie
);
3738 nickserv_free_cookie(cookie
);
3743 nickserv_saxdb_read(dict_t db
) {
3745 struct record_data
*rd
;
3747 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3749 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3754 static NICKSERV_FUNC(cmd_mergedb
)
3756 struct timeval start
, stop
;
3759 NICKSERV_MIN_PARMS(2);
3760 gettimeofday(&start
, NULL
);
3761 if (!(db
= parse_database(argv
[1]))) {
3762 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3765 nickserv_saxdb_read(db
);
3767 gettimeofday(&stop
, NULL
);
3768 stop
.tv_sec
-= start
.tv_sec
;
3769 stop
.tv_usec
-= start
.tv_usec
;
3770 if (stop
.tv_usec
< 0) {
3772 stop
.tv_usec
+= 1000000;
3774 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3779 expire_handles(UNUSED_ARG(void *data
))
3781 dict_iterator_t it
, next
;
3783 struct handle_info
*hi
;
3785 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3786 next
= iter_next(it
);
3788 if ((hi
->opserv_level
> 0)
3790 || HANDLE_FLAGGED(hi
, FROZEN
)
3791 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3794 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3795 if ((now
- hi
->lastseen
) > expiry
) {
3796 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3797 nickserv_unregister_handle(hi
, NULL
, NULL
);
3801 if (nickserv_conf
.handle_expire_frequency
)
3802 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3806 nickserv_load_dict(const char *fname
)
3810 if (!(file
= fopen(fname
, "r"))) {
3811 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3814 while (!feof(file
)) {
3815 fgets(line
, sizeof(line
), file
);
3818 if (line
[strlen(line
)-1] == '\n')
3819 line
[strlen(line
)-1] = 0;
3820 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3823 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3826 static enum reclaim_action
3827 reclaim_action_from_string(const char *str
) {
3829 return RECLAIM_NONE
;
3830 else if (!irccasecmp(str
, "warn"))
3831 return RECLAIM_WARN
;
3832 else if (!irccasecmp(str
, "svsnick"))
3833 return RECLAIM_SVSNICK
;
3834 else if (!irccasecmp(str
, "kill"))
3835 return RECLAIM_KILL
;
3837 return RECLAIM_NONE
;
3841 nickserv_conf_read(void)
3843 dict_t conf_node
, child
;
3847 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3848 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3851 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3853 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3854 if (nickserv_conf
.valid_handle_regex_set
)
3855 regfree(&nickserv_conf
.valid_handle_regex
);
3857 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3858 nickserv_conf
.valid_handle_regex_set
= !err
;
3859 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3861 nickserv_conf
.valid_handle_regex_set
= 0;
3863 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3864 if (nickserv_conf
.valid_nick_regex_set
)
3865 regfree(&nickserv_conf
.valid_nick_regex
);
3867 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3868 nickserv_conf
.valid_nick_regex_set
= !err
;
3869 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3871 nickserv_conf
.valid_nick_regex_set
= 0;
3873 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3875 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3876 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3877 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3878 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3879 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3880 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3881 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3882 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3883 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3884 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3885 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3886 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3887 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3888 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3889 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3890 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3891 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3892 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3893 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3894 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3895 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3896 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3897 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3898 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3899 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3901 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3902 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3903 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3905 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3906 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3907 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3909 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3910 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3911 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3912 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3913 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3914 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3915 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3916 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3917 if (!nickserv_conf
.disable_nicks
) {
3918 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3919 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3920 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3921 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3922 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3923 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3924 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3925 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3927 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3928 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3929 const char *key
= iter_key(it
), *value
;
3933 if (!strncasecmp(key
, "uc_", 3))
3934 flag
= toupper(key
[3]);
3935 else if (!strncasecmp(key
, "lc_", 3))
3936 flag
= tolower(key
[3]);
3940 if ((pos
= handle_inverse_flags
[flag
])) {
3941 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3942 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3945 if (nickserv_conf
.weak_password_dict
)
3946 dict_delete(nickserv_conf
.weak_password_dict
);
3947 nickserv_conf
.weak_password_dict
= dict_new();
3948 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3949 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3950 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3951 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3953 nickserv_load_dict(str
);
3954 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3955 if (nickserv
&& str
)
3956 NickChange(nickserv
, str
, 0);
3957 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3958 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3959 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3960 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3961 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3962 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3963 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3964 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3965 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3966 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3967 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3968 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3969 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3970 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3971 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3972 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3973 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3974 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3975 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3976 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3978 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
3979 nickserv_conf
.auto_oper
= str
? str
: "";
3981 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
3982 nickserv_conf
.auto_admin
= str
? str
: "";
3984 str
= conf_get_data("server/network", RECDB_QSTRING
);
3985 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3986 if (!nickserv_conf
.auth_policer_params
) {
3987 nickserv_conf
.auth_policer_params
= policer_params_new();
3988 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3989 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3991 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3992 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3993 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3997 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3999 char newnick
[NICKLEN
+1];
4008 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4010 case RECLAIM_SVSNICK
:
4012 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4013 } while (GetUserH(newnick
));
4014 irc_svsnick(nickserv
, user
, newnick
);
4017 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4018 irc_kill(nickserv
, user
, msg
);
4024 nickserv_reclaim_p(void *data
) {
4025 struct userNode
*user
= data
;
4026 struct nick_info
*ni
= get_nick_info(user
->nick
);
4028 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4032 check_user_nick(struct userNode
*user
) {
4033 struct nick_info
*ni
;
4034 user
->modes
&= ~FLAGS_REGNICK
;
4035 if (!(ni
= get_nick_info(user
->nick
)))
4037 if (user
->handle_info
== ni
->owner
) {
4038 user
->modes
|= FLAGS_REGNICK
;
4042 if (nickserv_conf
.warn_nick_owned
)
4043 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4044 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4046 if (nickserv_conf
.auto_reclaim_delay
)
4047 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4049 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4054 handle_new_user(struct userNode
*user
)
4056 return check_user_nick(user
);
4060 handle_account(struct userNode
*user
, const char *stamp
)
4062 struct handle_info
*hi
;
4065 #ifdef WITH_PROTOCOL_P10
4066 time_t timestamp
= 0;
4068 colon
= strchr(stamp
, ':');
4069 if(colon
&& colon
[1])
4072 timestamp
= atoi(colon
+1);
4074 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4075 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4077 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
);
4081 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4082 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4086 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4089 set_user_handle_info(user
, hi
, 0);
4091 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4096 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4098 struct handle_info
*hi
;
4100 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4101 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4102 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4104 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4105 check_user_nick(user
);
4109 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4111 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4112 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4113 set_user_handle_info(user
, NULL
, 0);
4116 static struct modcmd
*
4117 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4119 if (min_level
> 0) {
4121 sprintf(buf
, "%u", min_level
);
4122 if (must_be_qualified
) {
4123 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4125 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4127 } else if (min_level
== 0) {
4128 if (must_be_qualified
) {
4129 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4131 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4134 if (must_be_qualified
) {
4135 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4137 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4143 nickserv_db_cleanup(void)
4145 unreg_del_user_func(nickserv_remove_user
);
4146 userList_clean(&curr_helpers
);
4147 policer_params_delete(nickserv_conf
.auth_policer_params
);
4148 dict_delete(nickserv_handle_dict
);
4149 dict_delete(nickserv_nick_dict
);
4150 dict_delete(nickserv_opt_dict
);
4151 dict_delete(nickserv_allow_auth_dict
);
4152 dict_delete(nickserv_email_dict
);
4153 dict_delete(nickserv_id_dict
);
4154 dict_delete(nickserv_conf
.weak_password_dict
);
4155 free(auth_func_list
);
4156 free(unreg_func_list
);
4158 free(allowauth_func_list
);
4159 free(handle_merge_func_list
);
4160 free(failpw_func_list
);
4161 if (nickserv_conf
.valid_handle_regex_set
)
4162 regfree(&nickserv_conf
.valid_handle_regex
);
4163 if (nickserv_conf
.valid_nick_regex_set
)
4164 regfree(&nickserv_conf
.valid_nick_regex
);
4168 init_nickserv(const char *nick
)
4171 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4172 reg_new_user_func(handle_new_user
);
4173 reg_nick_change_func(handle_nick_change
);
4174 reg_del_user_func(nickserv_remove_user
);
4175 reg_account_func(handle_account
);
4177 /* set up handle_inverse_flags */
4178 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4179 for (i
=0; handle_flags
[i
]; i
++) {
4180 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4181 flag_access_levels
[i
] = 0;
4184 conf_register_reload(nickserv_conf_read
);
4185 nickserv_opt_dict
= dict_new();
4186 nickserv_email_dict
= dict_new();
4187 dict_set_free_keys(nickserv_email_dict
, free
);
4188 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4190 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4191 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4192 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4193 * a big pain to disable since its nolonger in the config file. ) -Rubin
4195 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4196 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4197 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4198 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4199 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4200 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4201 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4202 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4203 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4204 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4205 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4206 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4207 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4208 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4209 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4210 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4211 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4212 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4213 if (!nickserv_conf
.disable_nicks
) {
4214 /* nick management commands */
4215 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4216 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4217 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4218 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4219 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4220 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4222 if (nickserv_conf
.email_enabled
) {
4223 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4224 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4225 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4226 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4227 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4228 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4230 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4231 /* miscellaneous commands */
4232 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4233 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4234 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4235 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4236 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4238 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4239 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4240 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4241 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4242 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4243 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4244 /* dict_insert(nickserv_opt_dict, "STYLE", opt_style); */
4245 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4246 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4247 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4248 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4249 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4250 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4251 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4252 if (nickserv_conf
.titlehost_suffix
) {
4253 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4254 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4256 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4257 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4258 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4260 nickserv_handle_dict
= dict_new();
4261 dict_set_free_keys(nickserv_handle_dict
, free
);
4262 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4264 nickserv_id_dict
= dict_new();
4265 dict_set_free_keys(nickserv_id_dict
, free
);
4267 nickserv_nick_dict
= dict_new();
4268 dict_set_free_data(nickserv_nick_dict
, free
);
4270 nickserv_allow_auth_dict
= dict_new();
4272 userList_init(&curr_helpers
);
4275 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4276 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4277 nickserv_service
= service_register(nickserv
);
4279 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4280 reg_exit_func(nickserv_db_cleanup
);
4281 if(nickserv_conf
.handle_expire_frequency
)
4282 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4283 message_register_table(msgtab
);