1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
32 #include <tre/regex.h>
35 #include <ldap.h> /* just needed for default LDAP_PORT */
38 #define NICKSERV_CONF_NAME "services/nickserv"
40 #define KEY_DISABLE_NICKS "disable_nicks"
41 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
42 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
43 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
44 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
45 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
46 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
47 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
48 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
49 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
50 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
51 #define KEY_VALID_FAKEHOST_REGEX "valid_fakehost_regex"
52 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
53 #define KEY_MODOPER_LEVEL "modoper_level"
54 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
55 #define KEY_SET_TITLE_LEVEL "set_title_level"
56 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
57 #define KEY_DENIED_FAKEHOST_WORDS "denied_fakehost_words"
58 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
59 #define KEY_AUTO_OPER "auto_oper"
60 #define KEY_AUTO_ADMIN "auto_admin"
61 #define KEY_FLAG_LEVELS "flag_levels"
62 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
63 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
64 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
65 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
66 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
67 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
68 #define KEY_DICT_FILE "dict_file"
69 #define KEY_NICK "nick"
70 #define KEY_LANGUAGE "language"
71 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
72 #define KEY_AUTOGAG_DURATION "autogag_duration"
73 #define KEY_AUTH_POLICER "auth_policer"
74 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
75 #define KEY_EMAIL_ENABLED "email_enabled"
76 #define KEY_EMAIL_REQUIRED "email_required"
77 #define KEY_SYNC_LOG "sync_log"
78 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
79 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
80 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
81 #define KEY_DEFAULT_STYLE "default_style"
84 #define KEY_PASSWD "passwd"
85 #define KEY_NICKS "nicks"
86 #define KEY_MASKS "masks"
87 #define KEY_IGNORES "ignores"
88 #define KEY_OPSERV_LEVEL "opserv_level"
89 #define KEY_FLAGS "flags"
90 #define KEY_REGISTER_ON "register"
91 #define KEY_LAST_SEEN "lastseen"
92 #define KEY_INFO "info"
93 #define KEY_USERLIST_STYLE "user_style"
94 #define KEY_SCREEN_WIDTH "screen_width"
95 #define KEY_LAST_AUTHED_HOST "last_authed_host"
96 #define KEY_LAST_QUIT_HOST "last_quit_host"
97 #define KEY_EMAIL_ADDR "email_addr"
98 #define KEY_COOKIE "cookie"
99 #define KEY_COOKIE_DATA "data"
100 #define KEY_COOKIE_TYPE "type"
101 #define KEY_COOKIE_EXPIRES "expires"
102 #define KEY_ACTIVATION "activation"
103 #define KEY_PASSWORD_CHANGE "password change"
104 #define KEY_EMAIL_CHANGE "email change"
105 #define KEY_ALLOWAUTH "allowauth"
106 #define KEY_EPITHET "epithet"
107 #define KEY_TABLE_WIDTH "table_width"
108 #define KEY_ANNOUNCEMENTS "announcements"
109 #define KEY_MAXLOGINS "maxlogins"
110 #define KEY_FAKEHOST "fakehost"
111 #define KEY_NOTE_NOTE "note"
112 #define KEY_NOTE_SETTER "setter"
113 #define KEY_NOTE_DATE "date"
115 #define KEY_LDAP_ENABLE "ldap_enable"
118 #define KEY_LDAP_HOST "ldap_host"
119 #define KEY_LDAP_PORT "ldap_port"
120 #define KEY_LDAP_BASE "ldap_base"
121 #define KEY_LDAP_DN_FMT "ldap_dn_fmt"
122 #define KEY_LDAP_VERSION "ldap_version"
123 #define KEY_LDAP_AUTOCREATE "ldap_autocreate"
124 #define KEY_LDAP_ADMIN_DN "ldap_admin_dn"
125 #define KEY_LDAP_ADMIN_PASS "ldap_admin_pass"
126 #define KEY_LDAP_FIELD_ACCOUNT "ldap_field_account"
127 #define KEY_LDAP_FIELD_PASSWORD "ldap_field_password"
128 #define KEY_LDAP_FIELD_EMAIL "ldap_field_email"
131 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
133 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
134 #define OPTION_FUNC(NAME) int NAME(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
135 typedef OPTION_FUNC(option_func_t
);
137 DEFINE_LIST(handle_info_list
, struct handle_info
*);
139 #define NICKSERV_MIN_PARMS(N) do { \
141 reply("MSG_MISSING_PARAMS", argv[0]); \
142 svccmd_send_help_brief(user, nickserv, cmd); \
146 struct userNode
*nickserv
;
147 struct userList curr_helpers
;
148 const char *handle_flags
= HANDLE_FLAGS
;
150 extern struct string_list
*autojoin_channels
;
151 static struct module *nickserv_module
;
152 static struct service
*nickserv_service
;
153 static struct log_type
*NS_LOG
;
154 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
155 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
156 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
157 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
158 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
159 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
160 static char handle_inverse_flags
[256];
161 static unsigned int flag_access_levels
[32];
162 static const struct message_entry msgtab
[] = {
163 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
164 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
165 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
166 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
167 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
168 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
169 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
170 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
171 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
172 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
173 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
174 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
175 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
176 { "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." },
177 { "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." },
178 { "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." },
179 { "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." },
180 { "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." },
181 { "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." },
182 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
183 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
184 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
185 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
186 { "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." },
187 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
188 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
189 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
190 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
191 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
192 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
193 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
194 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
195 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
196 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
197 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
198 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
199 { "NSMSG_REGISTER_BAD_NICKMASK", "You must provide a hostmask, or online nick to generate one automatically. (or set a default hostmask in the config such as *@*)." },
200 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
201 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
202 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
203 { "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)" },
204 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
205 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
206 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
207 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
208 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
209 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
210 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
211 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
212 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
213 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
214 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
215 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
216 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
217 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
218 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
219 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
220 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
221 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
222 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
223 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
224 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
225 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
226 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
227 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
228 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
229 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
230 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
231 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
232 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
233 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
234 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
235 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
236 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
237 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
238 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
239 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
240 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
241 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
242 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
243 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
244 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
245 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
246 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
247 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
248 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
249 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
250 { "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)." },
251 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
252 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
253 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
254 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
255 { "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." },
256 { "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." },
257 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
258 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
259 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
260 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
261 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
262 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
263 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
264 { "NSMSG_PASS_SUCCESS", "Password changed." },
265 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
266 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
267 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
268 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
269 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
270 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
271 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
272 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
273 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
274 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
275 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
276 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
277 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
278 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
279 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
280 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
281 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
282 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
283 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
284 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
285 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
286 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
287 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
288 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
289 { "NSMSG_NO_ACCESS", "Access denied." },
290 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
291 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
292 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
293 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
294 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
295 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
296 { "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." },
297 { "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." },
298 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
299 { "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." },
300 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
301 { "NSMSG_SEARCH_MATCH", "Match: %s" },
302 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
303 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
304 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
305 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
306 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
307 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
308 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
309 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
310 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
311 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
312 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
313 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
314 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
315 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
316 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
317 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
318 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
319 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
320 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
321 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
322 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
323 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
324 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
325 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
326 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
327 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
328 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
329 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
330 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
331 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
332 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
333 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
334 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
335 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
337 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
338 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
340 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
341 { "NSEMAIL_ACTIVATION_BODY",
342 "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"
344 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
345 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
346 "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"
347 "/msg %3$s@%4$s AUTH %5$s your-password\n"
348 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
349 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
351 "If you did NOT request this account, you do not need to do anything.\n"
352 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
353 { "NSEMAIL_ACTIVATION_BODY_WEB",
354 "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"
356 "To verify your email address and complete the account registration, visit the following URL:\n"
357 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
359 "If you did NOT request this account, you do not need to do anything.\n"
360 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
361 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
362 { "NSEMAIL_PASSWORD_CHANGE_BODY",
363 "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"
364 "To complete the password change, log on to %1$s and type the following command:\n"
365 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
366 "If you did NOT request your password to be changed, you do not need to do anything.\n"
367 "Please contact the %1$s staff if you have questions." },
368 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
369 "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"
370 "To complete the password change, click the following URL:\n"
371 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
372 "If you did NOT request your password to be changed, you do not need to do anything.\n"
373 "Please contact the %1$s staff if you have questions." },
374 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
375 #ifdef stupid_verify_old_email
376 { "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." },
377 { "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." },
379 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
380 { "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." },
381 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
382 { "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." },
383 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
384 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
385 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
386 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
387 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
388 { "NSMSG_NOT_VALID_FAKEHOST_REGEX", "$b%s$b is not allowed by the admin, consult the valid vhost regex pattern in the config file under nickserv/valid_fakehost_regex." },
389 { "CHECKPASS_YES", "Yes." },
390 { "CHECKPASS_NO", "No." },
391 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
395 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
396 static void nickserv_reclaim_p(void *data
);
398 struct nickserv_config nickserv_conf
;
400 /* We have 2^32 unique account IDs to use. */
401 unsigned long int highest_id
= 0;
404 canonicalize_hostmask(char *mask
)
406 char *out
= mask
, *temp
;
407 if ((temp
= strchr(mask
, '!'))) {
409 while (*temp
) *out
++ = *temp
++;
415 static struct handle_note
*
416 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
418 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
420 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
422 memcpy(note
->note
, text
, strlen(text
));
426 static struct handle_info
*
427 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
429 struct handle_info
*hi
;
431 hi
= calloc(1, sizeof(*hi
));
432 hi
->userlist_style
= HI_DEFAULT_STYLE
;
433 hi
->announcements
= '?';
434 hi
->handle
= strdup(handle
);
435 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
437 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
443 register_nick(const char *nick
, struct handle_info
*owner
)
445 struct nick_info
*ni
;
446 ni
= malloc(sizeof(struct nick_info
));
447 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
449 ni
->next
= owner
->nicks
;
451 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
455 delete_nick(struct nick_info
*ni
)
457 struct nick_info
*last
, *next
;
458 struct userNode
*user
;
459 /* Check to see if we should mark a user as unregistered. */
460 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
461 user
->modes
&= ~FLAGS_REGNICK
;
464 /* Remove ni from the nick_info linked list. */
465 if (ni
== ni
->owner
->nicks
) {
466 ni
->owner
->nicks
= ni
->next
;
468 last
= ni
->owner
->nicks
;
474 last
->next
= next
->next
;
476 dict_remove(nickserv_nick_dict
, ni
->nick
);
479 static unreg_func_t
*unreg_func_list
;
480 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
483 reg_unreg_func(unreg_func_t func
)
485 if (unreg_func_used
== unreg_func_size
) {
486 if (unreg_func_size
) {
487 unreg_func_size
<<= 1;
488 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
491 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
494 unreg_func_list
[unreg_func_used
++] = func
;
498 nickserv_free_cookie(void *data
)
500 struct handle_cookie
*cookie
= data
;
501 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
502 if (cookie
->data
) free(cookie
->data
);
507 free_handle_info(void *vhi
)
509 struct handle_info
*hi
= vhi
;
511 free_string_list(hi
->masks
);
512 free_string_list(hi
->ignores
);
516 delete_nick(hi
->nicks
);
522 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
523 nickserv_free_cookie(hi
->cookie
);
525 if (hi
->email_addr
) {
526 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
527 handle_info_list_remove(hil
, hi
);
529 dict_remove(nickserv_email_dict
, hi
->email_addr
);
534 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
537 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
540 struct userNode
*uNode
;
542 for (n
=0; n
<unreg_func_used
; n
++)
543 unreg_func_list
[n
](notify
, hi
);
545 if (nickserv_conf
.sync_log
) {
546 uNode
= GetUserH(hi
->users
->nick
);
550 set_user_handle_info(hi
->users
, NULL
, 0);
553 if (nickserv_conf
.disable_nicks
)
554 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
556 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
559 if (nickserv_conf
.sync_log
)
560 SyncLog("UNREGISTER %s", hi
->handle
);
562 dict_remove(nickserv_handle_dict
, hi
->handle
);
566 get_handle_info(const char *handle
)
568 return dict_find(nickserv_handle_dict
, handle
, 0);
572 get_nick_info(const char *nick
)
574 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
578 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
583 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
584 mn
= channel
->members
.list
[nn
];
585 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
592 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
593 if (!user
->handle_info
) {
595 send_message(user
, bot
, "MSG_AUTHENTICATE");
599 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
601 send_message(user
, bot
, "NSMSG_NO_ACCESS");
605 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
607 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
611 if (user
->handle_info
->opserv_level
< min_level
) {
613 send_message(user
, bot
, "NSMSG_NO_ACCESS");
621 is_valid_handle(const char *handle
)
623 struct userNode
*user
;
624 /* cant register a juped nick/service nick as handle, to prevent confusion */
625 user
= GetUserH(handle
);
626 if (user
&& IsLocal(user
))
628 /* check against maximum length */
629 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
631 /* for consistency, only allow account names that could be nicks */
632 if (!is_valid_nick(handle
))
634 /* disallow account names that look like bad words */
635 if (opserv_bad_channel(handle
))
637 /* test either regex or containing all valid chars */
638 if (nickserv_conf
.valid_handle_regex_set
) {
639 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
642 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
643 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
647 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
652 is_registerable_nick(const char *nick
)
654 /* make sure it could be used as an account name */
655 if (!is_valid_handle(nick
))
658 if (strlen(nick
) > NICKLEN
)
660 /* test either regex or as valid handle */
661 if (nickserv_conf
.valid_nick_regex_set
) {
662 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
665 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
666 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
672 /* this has been replaced with one in tools.c
675 is_valid_email_addr(const char *email)
677 return strchr(email, '@') != NULL;
683 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
685 if (hi
->email_addr
) {
686 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
687 return hi
->email_addr
;
697 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
699 struct handle_info
*hi
;
700 struct userNode
*target
;
704 if (!(hi
= get_handle_info(++name
))) {
705 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
710 if (!(target
= GetUserH(name
))) {
711 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
714 if (IsLocal(target
)) {
715 if (IsService(target
))
716 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
718 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
721 if (!(hi
= target
->handle_info
)) {
722 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
730 oper_outranks(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
) {
731 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
733 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
734 if ((user
->handle_info
->opserv_level
== 1000)
735 || (user
->handle_info
== hi
)
736 || ((user
->handle_info
->opserv_level
== 0)
737 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
738 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
742 reply("MSG_USER_OUTRANKED", hi
->handle
);
747 get_victim_oper(struct svccmd
*cmd
, struct userNode
*user
, const char *target
)
749 struct handle_info
*hi
;
750 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
752 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
753 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
756 return oper_outranks(cmd
, user
, hi
) ? hi
: NULL
;
760 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
764 /* If no hostmasks on the account, allow it. */
765 if (!hi
->masks
->used
)
767 /* If any hostmask matches, allow it. */
768 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
769 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
771 /* If they are allowauthed to this account, allow it (removing the aa). */
772 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
773 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
776 /* The user is not allowed to use this account. */
781 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
784 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
788 if (len
< nickserv_conf
.password_min_length
) {
790 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
793 if (!irccasecmp(pass
, handle
)) {
795 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
798 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
801 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
804 for (i
=0; i
<len
; i
++) {
805 if (isdigit(pass
[i
]))
807 if (isupper(pass
[i
]))
809 if (islower(pass
[i
]))
812 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
813 || (cnt_upper
< nickserv_conf
.password_min_upper
)
814 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
816 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
822 static auth_func_t
*auth_func_list
;
823 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
826 reg_auth_func(auth_func_t func
)
828 if (auth_func_used
== auth_func_size
) {
829 if (auth_func_size
) {
830 auth_func_size
<<= 1;
831 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
834 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
837 auth_func_list
[auth_func_used
++] = func
;
840 static handle_rename_func_t
*rf_list
;
841 static unsigned int rf_list_size
, rf_list_used
;
844 reg_handle_rename_func(handle_rename_func_t func
)
846 if (rf_list_used
== rf_list_size
) {
849 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
852 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
855 rf_list
[rf_list_used
++] = func
;
859 generate_fakehost(struct handle_info
*handle
)
861 struct userNode
*target
;
862 extern const char *hidden_host_suffix
;
863 static char buffer
[HOSTLEN
+1];
867 if (!handle
->fakehost
) {
868 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
873 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
874 else if (style
== 2) {
875 /* Due to the way fakehost is coded theres no way i can
876 get the exact user, so for now ill just take the first
878 for (target
= handle
->users
; target
; target
= target
->next_authed
)
881 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
884 } else if (handle
->fakehost
[0] == '.') {
885 /* A leading dot indicates the stored value is actually a title. */
886 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
889 return handle
->fakehost
;
893 apply_fakehost(struct handle_info
*handle
)
895 struct userNode
*target
;
900 fake
= generate_fakehost(handle
);
901 for (target
= handle
->users
; target
; target
= target
->next_authed
)
902 assign_fakehost(target
, fake
, 1);
905 void send_func_list(struct userNode
*user
)
908 struct handle_info
*old_info
;
910 old_info
= user
->handle_info
;
912 for (n
=0; n
<auth_func_used
; n
++)
913 auth_func_list
[n
](user
, old_info
);
917 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
920 struct handle_info
*old_info
;
922 /* This can happen if somebody uses COOKIE while authed, or if
923 * they re-auth to their current handle (which is silly, but users
925 if (user
->handle_info
== hi
)
928 if (user
->handle_info
) {
929 struct userNode
*other
;
932 userList_remove(&curr_helpers
, user
);
934 /* remove from next_authed linked list */
935 if (user
->handle_info
->users
== user
) {
936 user
->handle_info
->users
= user
->next_authed
;
938 for (other
= user
->handle_info
->users
;
939 other
->next_authed
!= user
;
940 other
= other
->next_authed
) ;
941 other
->next_authed
= user
->next_authed
;
943 /* if nobody left on old handle, and they're not an oper, remove !god */
944 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
945 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
946 /* record them as being last seen at this time */
947 user
->handle_info
->lastseen
= now
;
948 /* and record their hostmask */
949 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
951 old_info
= user
->handle_info
;
952 user
->handle_info
= hi
;
953 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
954 HANDLE_CLEAR_FLAG(hi
, HELPING
);
956 /* Call auth handlers */
957 if (!GetUserH(user
->nick
))
961 struct nick_info
*ni
;
963 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
964 if (nickserv_conf
.warn_clone_auth
) {
965 struct userNode
*other
;
966 for (other
= hi
->users
; other
; other
= other
->next_authed
)
967 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
970 /* Add this auth to users list of current auths */
971 user
->next_authed
= hi
->users
;
974 /* Add to helpers list */
976 userList_append(&curr_helpers
, user
);
978 /* Set the fakehost */
979 if (hi
->fakehost
|| old_info
)
983 #ifdef WITH_PROTOCOL_P10
984 /* Stamp users with their account name. */
985 char *id
= hi
->handle
;
987 const char *id
= "???";
989 /* Mark all the nicks registered to this
990 * account as registered nicks
991 * - Why not just this one? -rubin */
992 if (!nickserv_conf
.disable_nicks
) {
993 struct nick_info
*ni
;
994 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
995 if (!irccasecmp(user
->nick
, ni
->nick
)) {
996 user
->modes
|= FLAGS_REGNICK
;
1001 /* send the account to the ircd */
1002 StampUser(user
, id
, hi
->registered
);
1005 /* Stop trying to kick this user off their nick */
1006 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1007 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1009 /* We cannot clear the user's account ID, unfortunately. */
1010 user
->next_authed
= NULL
;
1013 /* Call auth handlers */
1014 if (GetUserH(user
->nick
)) {
1015 for (n
=0; n
<auth_func_used
; n
++)
1016 auth_func_list
[n
](user
, old_info
);
1020 static struct handle_info
*
1021 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1023 struct handle_info
*hi
;
1024 struct nick_info
*ni
;
1025 char crypted
[MD5_CRYPT_LENGTH
];
1027 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1028 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1032 if(strlen(handle
) > 15)
1034 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1038 if (!is_secure_password(handle
, passwd
, user
))
1041 cryptpass(passwd
, crypted
);
1042 hi
= register_handle(handle
, crypted
, 0);
1043 hi
->masks
= alloc_string_list(1);
1044 hi
->ignores
= alloc_string_list(1);
1046 hi
->language
= lang_C
;
1047 hi
->registered
= now
;
1049 hi
->flags
= HI_DEFAULT_FLAGS
;
1050 if (settee
&& !no_auth
)
1051 set_user_handle_info(settee
, hi
, 1);
1054 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1055 else if (nickserv_conf
.disable_nicks
)
1056 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1057 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1058 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1060 register_nick(user
->nick
, hi
);
1061 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1063 if (settee
&& (user
!= settee
))
1064 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1066 ldap_do_add(handle
, passwd
, hi
->email_addr
);
1072 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1074 cookie
->hi
->cookie
= cookie
;
1075 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1078 /* Contributed by the great sneep of afternet ;) */
1079 /* Since this gets used in a URL, we want to avoid stuff that confuses
1080 * email clients such as ] and ?. a-z, 0-9 only.
1082 void genpass(char *str
, int len
)
1087 for(i
= 0; i
< len
; i
++)
1091 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1092 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1100 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1102 struct handle_cookie
*cookie
;
1103 char subject
[128], body
[4096], *misc
;
1104 const char *netname
, *fmt
;
1108 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1112 cookie
= calloc(1, sizeof(*cookie
));
1114 cookie
->type
= type
;
1115 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1117 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1118 /* Adding dedicated password gen function for more control -Rubin */
1119 genpass(cookie
->cookie
, 10);
1121 *inttobase64(cookie->cookie, rand(), 5);
1122 *inttobase64(cookie->cookie+5, rand(), 5);
1125 netname
= nickserv_conf
.network_name
;
1128 switch (cookie
->type
) {
1130 hi
->passwd
[0] = 0; /* invalidate password */
1131 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1132 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1133 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1136 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1138 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1140 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1143 case PASSWORD_CHANGE
:
1144 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1145 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1146 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1148 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1150 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1151 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1154 misc
= hi
->email_addr
;
1155 hi
->email_addr
= cookie
->data
;
1156 #ifdef stupid_verify_old_email
1158 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1159 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1160 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1161 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1162 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1163 sendmail(nickserv
, hi
, subject
, body
, 1);
1164 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1165 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1168 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1169 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1170 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1171 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1172 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1173 sendmail(nickserv
, hi
, subject
, body
, 1);
1175 #ifdef stupid_verify_old_email
1178 hi
->email_addr
= misc
;
1181 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1182 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1183 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1184 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1185 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1188 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1192 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1193 nickserv_bake_cookie(cookie
);
1197 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1199 cookie
->hi
->cookie
= NULL
;
1200 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1201 nickserv_free_cookie(cookie
);
1205 nickserv_free_email_addr(void *data
)
1207 handle_info_list_clean(data
);
1212 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1214 struct handle_info_list
*hil
;
1215 /* Remove from old handle_info_list ... */
1216 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1217 handle_info_list_remove(hil
, hi
);
1218 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1219 hi
->email_addr
= NULL
;
1221 /* Add to the new list.. */
1222 if (new_email_addr
) {
1223 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1224 hil
= calloc(1, sizeof(*hil
));
1225 hil
->tag
= strdup(new_email_addr
);
1226 handle_info_list_init(hil
);
1227 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1229 handle_info_list_append(hil
, hi
);
1230 hi
->email_addr
= hil
->tag
;
1234 static NICKSERV_FUNC(cmd_register
)
1237 struct handle_info
*hi
;
1238 const char *email_addr
, *password
;
1239 char syncpass
[MD5_CRYPT_LENGTH
];
1240 int no_auth
, weblink
;
1242 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1243 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1247 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1248 /* Require the first handle registered to belong to someone +o. */
1249 reply("NSMSG_REQUIRE_OPER");
1253 if (user
->handle_info
) {
1254 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1258 if (IsRegistering(user
)) {
1259 reply("NSMSG_ALREADY_REGISTERING");
1263 if (IsStamped(user
)) {
1264 /* Unauthenticated users might still have been stamped
1265 previously and could therefore have a hidden host;
1266 do not allow them to register a new account. */
1267 reply("NSMSG_STAMPED_REGISTER");
1271 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1273 if (!is_valid_handle(argv
[1])) {
1274 reply("NSMSG_BAD_HANDLE", argv
[1]);
1279 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1280 struct handle_info_list
*hil
;
1283 /* Remember email address. */
1284 email_addr
= argv
[3];
1286 /* Check that the email address looks valid.. */
1287 if (!valid_email(email_addr
)) {
1288 reply("NSMSG_BAD_EMAIL_ADDR");
1292 /* .. and that we are allowed to send to it. */
1293 if ((str
= sendmail_prohibited_address(email_addr
))) {
1294 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1298 /* If we do email verify, make sure we don't spam the address. */
1299 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1301 for (nn
=0; nn
<hil
->used
; nn
++) {
1302 if (hil
->list
[nn
]->cookie
) {
1303 reply("NSMSG_EMAIL_UNACTIVATED");
1307 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1308 reply("NSMSG_EMAIL_OVERUSED");
1321 /* Webregister hack - send URL instead of IRC cookie
1324 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1328 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1330 /* Add any masks they should get. */
1331 if (nickserv_conf
.default_hostmask
) {
1332 string_list_append(hi
->masks
, strdup("*@*"));
1334 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1335 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1336 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1339 /* If they're the first to register, give them level 1000. */
1340 if (dict_size(nickserv_handle_dict
) == 1) {
1341 hi
->opserv_level
= 1000;
1342 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1345 /* Set their email address. */
1347 nickserv_set_email_addr(hi
, email_addr
);
1349 /* If they need to do email verification, tell them. */
1351 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1353 /* Set registering flag.. */
1354 user
->modes
|= FLAGS_REGISTERING
;
1356 if (nickserv_conf
.sync_log
) {
1357 cryptpass(password
, syncpass
);
1359 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1360 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1363 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1366 /* this wont work if email is required .. */
1367 process_adduser_pending(user
);
1372 static NICKSERV_FUNC(cmd_oregister
)
1374 struct userNode
*settee
= NULL
;
1375 struct handle_info
*hi
;
1376 char* account
= NULL
;
1382 NICKSERV_MIN_PARMS(3);
1386 if (nickserv_conf
.email_required
) {
1387 NICKSERV_MIN_PARMS(4);
1389 if (argc
>= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1390 if (strchr(argv
[4], '@') || argc
>= 6) /* If @, its mask not nick */
1400 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1401 if (strchr(argv
[3], '@') || argc
>= 5) /* If @, its mask not nick */
1410 /* If they passed a nick, look for that user.. */
1411 if (nick
&& !(settee
= GetUserH(nick
))) {
1412 reply("MSG_NICK_UNKNOWN", argv
[4]);
1415 /* If the setee is already authed, we cant add a 2nd account for them.. */
1416 if (settee
&& settee
->handle_info
) {
1417 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1420 /* If there is no default mask in the conf, and they didn't pass a mask,
1421 * but we did find a user by nick, generate the mask */
1423 if (nickserv_conf
.default_hostmask
)
1426 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1428 reply("NSMSG_REGISTER_BAD_NICKMASK");
1433 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1434 return 0; /* error reply handled by above */
1437 nickserv_set_email_addr(hi
, email
);
1440 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1441 string_list_append(hi
->masks
, mask_canonicalized
);
1444 if (nickserv_conf
.sync_log
)
1445 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1450 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1453 struct userNode
*target
;
1454 char *new_mask
= strdup(pretty_mask(mask
));
1455 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1456 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1457 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1462 string_list_append(hi
->ignores
, new_mask
);
1463 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1465 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1466 irc_silence(target
, new_mask
, 1);
1471 static NICKSERV_FUNC(cmd_addignore
)
1473 NICKSERV_MIN_PARMS(2);
1475 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1478 static NICKSERV_FUNC(cmd_oaddignore
)
1480 struct handle_info
*hi
;
1482 NICKSERV_MIN_PARMS(3);
1483 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1486 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1490 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1493 struct userNode
*target
;
1494 char *pmask
= strdup(pretty_mask(del_mask
));
1495 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1496 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1497 char *old_mask
= hi
->ignores
->list
[i
];
1498 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1499 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1500 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1501 irc_silence(target
, old_mask
, 0);
1508 reply("NSMSG_DELMASK_NOT_FOUND");
1512 static NICKSERV_FUNC(cmd_delignore
)
1514 NICKSERV_MIN_PARMS(2);
1515 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1518 static NICKSERV_FUNC(cmd_odelignore
)
1520 struct handle_info
*hi
;
1521 NICKSERV_MIN_PARMS(3);
1522 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1524 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1527 static NICKSERV_FUNC(cmd_handleinfo
)
1530 unsigned int i
, pos
=0, herelen
;
1531 struct userNode
*target
, *next_un
;
1532 struct handle_info
*hi
;
1533 const char *nsmsg_none
;
1536 if (!(hi
= user
->handle_info
)) {
1537 reply("NSMSG_MUST_AUTH");
1540 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1544 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1545 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1547 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1550 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1551 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1553 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1556 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1557 if (HANDLE_FLAGGED(hi
, FROZEN
))
1558 reply("NSMSG_HANDLEINFO_VACATION");
1560 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1561 struct do_not_register
*dnr
;
1562 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1563 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1564 if (!oper_outranks(cmd
, user
, hi
))
1566 } else if (hi
!= user
->handle_info
) {
1567 reply("NSMSG_HANDLEINFO_END");
1571 if (nickserv_conf
.email_enabled
)
1572 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1576 switch (hi
->cookie
->type
) {
1577 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1578 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1579 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1580 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1581 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1587 unsigned long flen
= 1;
1588 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1590 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1591 if (hi
->flags
& 1 << i
)
1592 flags
[flen
++] = handle_flags
[i
];
1594 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1596 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1599 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1600 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1601 || (hi
->opserv_level
> 0)) {
1602 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1605 if (IsHelping(user
) || IsOper(user
))
1610 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1611 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1616 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1618 if (hi
->last_quit_host
[0])
1619 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1621 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1623 if (nickserv_conf
.disable_nicks
) {
1624 /* nicks disabled; don't show anything about registered nicks */
1625 } else if (hi
->nicks
) {
1626 struct nick_info
*ni
, *next_ni
;
1627 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1628 herelen
= strlen(ni
->nick
);
1629 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1631 goto print_nicks_buff
;
1635 memcpy(buff
+pos
, ni
->nick
, herelen
);
1636 pos
+= herelen
; buff
[pos
++] = ' ';
1640 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1645 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1648 if (hi
->masks
->used
) {
1649 for (i
=0; i
< hi
->masks
->used
; i
++) {
1650 herelen
= strlen(hi
->masks
->list
[i
]);
1651 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1653 goto print_mask_buff
;
1655 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1656 pos
+= herelen
; buff
[pos
++] = ' ';
1657 if (i
+1 == hi
->masks
->used
) {
1660 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1665 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1668 if (hi
->ignores
->used
) {
1669 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1670 herelen
= strlen(hi
->ignores
->list
[i
]);
1671 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1673 goto print_ignore_buff
;
1675 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1676 pos
+= herelen
; buff
[pos
++] = ' ';
1677 if (i
+1 == hi
->ignores
->used
) {
1680 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1685 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1689 struct userData
*channel
, *next
;
1692 for (channel
= hi
->channels
; channel
; channel
= next
) {
1693 next
= channel
->u_next
;
1694 name
= channel
->channel
->channel
->name
;
1695 herelen
= strlen(name
);
1696 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1698 goto print_chans_buff
;
1700 if (IsUserSuspended(channel
))
1702 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1706 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1711 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1714 for (target
= hi
->users
; target
; target
= next_un
) {
1715 herelen
= strlen(target
->nick
);
1716 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1718 goto print_cnick_buff
;
1720 next_un
= target
->next_authed
;
1722 memcpy(buff
+pos
, target
->nick
, herelen
);
1723 pos
+= herelen
; buff
[pos
++] = ' ';
1727 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1732 reply("NSMSG_HANDLEINFO_END");
1736 static NICKSERV_FUNC(cmd_userinfo
)
1738 struct userNode
*target
;
1740 NICKSERV_MIN_PARMS(2);
1741 if (!(target
= GetUserH(argv
[1]))) {
1742 reply("MSG_NICK_UNKNOWN", argv
[1]);
1745 if (target
->handle_info
)
1746 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1748 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1752 static NICKSERV_FUNC(cmd_nickinfo
)
1754 struct nick_info
*ni
;
1756 NICKSERV_MIN_PARMS(2);
1757 if (!(ni
= get_nick_info(argv
[1]))) {
1758 reply("MSG_NICK_UNKNOWN", argv
[1]);
1761 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1765 static NICKSERV_FUNC(cmd_rename_handle
)
1767 struct handle_info
*hi
;
1768 struct userNode
*uNode
;
1772 NICKSERV_MIN_PARMS(3);
1773 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1775 if (!is_valid_handle(argv
[2])) {
1776 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1779 if (get_handle_info(argv
[2])) {
1780 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1783 if(strlen(argv
[2]) > 15)
1785 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1789 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1790 hi
->handle
= strdup(argv
[2]);
1791 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1792 for (nn
=0; nn
<rf_list_used
; nn
++)
1793 rf_list
[nn
](hi
, old_handle
);
1795 if (nickserv_conf
.sync_log
) {
1796 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1797 irc_rename(uNode
, hi
->handle
);
1799 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1802 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1803 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1804 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1810 static failpw_func_t
*failpw_func_list
;
1811 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1814 reg_failpw_func(failpw_func_t func
)
1816 if (failpw_func_used
== failpw_func_size
) {
1817 if (failpw_func_size
) {
1818 failpw_func_size
<<= 1;
1819 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1821 failpw_func_size
= 8;
1822 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1825 failpw_func_list
[failpw_func_used
++] = func
;
1829 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1831 * called by nefariouses enhanced AC login-on-connect code
1834 struct handle_info
*loc_auth(char *handle
, char *password
)
1836 int pw_arg
, used
, maxlogins
;
1839 struct handle_info
*hi
;
1840 struct userNode
*other
;
1842 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1848 /* We don't know the users hostname, or anything because they
1849 * havn't registered yet. So we can only allow LOC if your
1850 * account has *@* as a hostmask.
1852 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1854 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1863 /* Responses from here on look up the language used by the handle they asked about. */
1864 if (!checkpass(password
, hi
->passwd
)) {
1867 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1870 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1871 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1872 if (++used
>= maxlogins
) {
1879 static NICKSERV_FUNC(cmd_auth
)
1881 int pw_arg
, used
, maxlogins
;
1882 struct handle_info
*hi
;
1884 struct userNode
*other
;
1886 int ldap_result
= 0;
1890 if (user
->handle_info
) {
1891 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1894 if (IsStamped(user
)) {
1895 /* Unauthenticated users might still have been stamped
1896 previously and could therefore have a hidden host;
1897 do not allow them to authenticate. */
1898 reply("NSMSG_STAMPED_AUTH");
1903 ldap_result
= ldap_check_auth(argv
[1], argv
[2]);
1905 /* pull the users info from ldap:
1907 * * name if available
1913 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1915 } else if (argc
== 2) {
1916 if (nickserv_conf
.disable_nicks
) {
1917 if (!(hi
= get_handle_info(user
->nick
))) {
1918 reply("NSMSG_HANDLE_NOT_FOUND");
1922 /* try to look up their handle from their nick */
1923 /* TODO: handle ldap auth on nickserv style networks, too */
1924 struct nick_info
*ni
;
1925 ni
= get_nick_info(user
->nick
);
1927 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1934 reply("MSG_MISSING_PARAMS", argv
[0]);
1935 svccmd_send_help_brief(user
, nickserv
, cmd
);
1940 if(ldap_result
== true && nickserv_conf
.ldap_autocreate
) {
1941 /* user not found, but authed to ldap successfully..
1942 * create the account.
1945 if(!(hi
= nickserv_register(user
, NULL
, argv
[1], argv
[2], 0))) {
1946 reply("NSMSG_UNABLE_TO_ADD");
1947 return 0; /* couldn't add the user for some reason */
1949 /* Add a *@* mask */
1950 if(nickserv_conf
.default_hostmask
)
1953 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1956 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1957 string_list_append(hi
->masks
, mask_canonicalized
);
1960 nickserv_set_email_addr(hi
, email
);
1962 if(nickserv_conf
.sync_log
)
1963 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
);
1967 reply("NSMSG_HANDLE_NOT_FOUND");
1973 /* Responses from here on look up the language used by the handle they asked about. */
1974 passwd
= argv
[pw_arg
];
1975 if (!valid_user_for(user
, hi
)) {
1976 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1977 send_message_type(4, user
, cmd
->parent
->bot
,
1978 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1981 send_message_type(4, user
, cmd
->parent
->bot
,
1982 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1984 argv
[pw_arg
] = "BADMASK";
1990 if (!checkpass(passwd
, hi
->passwd
)) {
1993 send_message_type(4, user
, cmd
->parent
->bot
,
1994 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1995 argv
[pw_arg
] = "BADPASS";
1996 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1997 if (nickserv_conf
.autogag_enabled
) {
1998 if (!user
->auth_policer
.params
) {
1999 user
->auth_policer
.last_req
= now
;
2000 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
2002 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
2004 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
2005 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
2006 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2008 argv
[pw_arg
] = "GAGGED";
2013 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2014 send_message_type(4, user
, cmd
->parent
->bot
,
2015 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2016 argv
[pw_arg
] = "SUSPENDED";
2019 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2020 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2021 if (++used
>= maxlogins
) {
2022 send_message_type(4, user
, cmd
->parent
->bot
,
2023 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2025 argv
[pw_arg
] = "MAXLOGINS";
2030 set_user_handle_info(user
, hi
, 1);
2031 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2032 reply("NSMSG_PLEASE_SET_EMAIL");
2033 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2034 reply("NSMSG_WEAK_PASSWORD");
2035 if (hi
->passwd
[0] != '$')
2036 cryptpass(passwd
, hi
->passwd
);
2038 /* If a channel was waiting for this user to auth,
2039 * finish adding them */
2040 process_adduser_pending(user
);
2042 reply("NSMSG_AUTH_SUCCESS");
2045 /* Set +x if autohide is on */
2046 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2047 irc_umode(user
, "+x");
2049 if(!IsOper(user
)) /* If they arnt already opered.. */
2051 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2052 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2054 irc_umode(user
,nickserv_conf
.auto_admin
);
2055 reply("NSMSG_AUTO_OPER_ADMIN");
2057 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2059 irc_umode(user
,nickserv_conf
.auto_oper
);
2060 reply("NSMSG_AUTO_OPER");
2064 /* Wipe out the pass for the logs */
2065 argv
[pw_arg
] = "****";
2069 static allowauth_func_t
*allowauth_func_list
;
2070 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2073 reg_allowauth_func(allowauth_func_t func
)
2075 if (allowauth_func_used
== allowauth_func_size
) {
2076 if (allowauth_func_size
) {
2077 allowauth_func_size
<<= 1;
2078 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2080 allowauth_func_size
= 8;
2081 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2084 allowauth_func_list
[allowauth_func_used
++] = func
;
2087 static NICKSERV_FUNC(cmd_allowauth
)
2089 struct userNode
*target
;
2090 struct handle_info
*hi
;
2093 NICKSERV_MIN_PARMS(2);
2094 if (!(target
= GetUserH(argv
[1]))) {
2095 reply("MSG_NICK_UNKNOWN", argv
[1]);
2098 if (target
->handle_info
) {
2099 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2102 if (IsStamped(target
)) {
2103 /* Unauthenticated users might still have been stamped
2104 previously and could therefore have a hidden host;
2105 do not allow them to authenticate to an account. */
2106 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2111 else if (!(hi
= get_handle_info(argv
[2]))) {
2112 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2116 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2117 reply("MSG_USER_OUTRANKED", hi
->handle
);
2120 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2121 || (hi
->opserv_level
> 0))
2122 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2123 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2126 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2127 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2128 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2129 if (nickserv_conf
.email_enabled
)
2130 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2132 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2133 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2135 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2137 for (n
=0; n
<allowauth_func_used
; n
++)
2138 allowauth_func_list
[n
](user
, target
, hi
);
2142 static NICKSERV_FUNC(cmd_authcookie
)
2144 struct handle_info
*hi
;
2146 NICKSERV_MIN_PARMS(2);
2147 if (user
->handle_info
) {
2148 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2151 if (IsStamped(user
)) {
2152 /* Unauthenticated users might still have been stamped
2153 previously and could therefore have a hidden host;
2154 do not allow them to authenticate to an account. */
2155 reply("NSMSG_STAMPED_AUTHCOOKIE");
2158 if (!(hi
= get_handle_info(argv
[1]))) {
2159 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2162 if (!hi
->email_addr
) {
2163 reply("MSG_SET_EMAIL_ADDR");
2166 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2170 static NICKSERV_FUNC(cmd_delcookie
)
2172 struct handle_info
*hi
;
2174 hi
= user
->handle_info
;
2176 reply("NSMSG_NO_COOKIE");
2179 switch (hi
->cookie
->type
) {
2182 reply("NSMSG_MUST_TIME_OUT");
2185 nickserv_eat_cookie(hi
->cookie
);
2186 reply("NSMSG_ATE_COOKIE");
2192 static NICKSERV_FUNC(cmd_odelcookie
)
2194 struct handle_info
*hi
;
2196 NICKSERV_MIN_PARMS(2);
2198 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2202 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2206 switch (hi
->cookie
->type
) {
2208 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2209 if (nickserv_conf
.sync_log
)
2210 SyncLog("ACCOUNTACC %s", hi
->handle
);
2212 case PASSWORD_CHANGE
:
2213 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2214 if (nickserv_conf
.sync_log
)
2215 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2218 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2219 if (nickserv_conf
.sync_log
)
2220 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2222 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2223 if (nickserv_conf
.sync_log
)
2224 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2227 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2228 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2232 nickserv_eat_cookie(hi
->cookie
);
2233 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2238 static NICKSERV_FUNC(cmd_resetpass
)
2240 struct handle_info
*hi
;
2241 char crypted
[MD5_CRYPT_LENGTH
];
2244 NICKSERV_MIN_PARMS(3);
2245 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2249 if (user
->handle_info
) {
2250 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2253 if (IsStamped(user
)) {
2254 /* Unauthenticated users might still have been stamped
2255 previously and could therefore have a hidden host;
2256 do not allow them to activate an account. */
2257 reply("NSMSG_STAMPED_RESETPASS");
2260 if (!(hi
= get_handle_info(argv
[1]))) {
2261 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2264 if (!hi
->email_addr
) {
2265 reply("MSG_SET_EMAIL_ADDR");
2268 cryptpass(argv
[2], crypted
);
2270 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2274 static NICKSERV_FUNC(cmd_cookie
)
2276 struct handle_info
*hi
;
2279 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2282 NICKSERV_MIN_PARMS(3);
2283 if (!(hi
= get_handle_info(argv
[1]))) {
2284 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2290 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2291 reply("NSMSG_HANDLE_SUSPENDED");
2296 reply("NSMSG_NO_COOKIE");
2300 /* Check validity of operation before comparing cookie to
2301 * prohibit guessing by authed users. */
2302 if (user
->handle_info
2303 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2304 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2305 reply("NSMSG_CANNOT_COOKIE");
2309 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2310 reply("NSMSG_BAD_COOKIE");
2314 switch (hi
->cookie
->type
) {
2316 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2317 set_user_handle_info(user
, hi
, 1);
2318 reply("NSMSG_HANDLE_ACTIVATED");
2319 if (nickserv_conf
.sync_log
)
2320 SyncLog("ACCOUNTACC %s", hi
->handle
);
2322 case PASSWORD_CHANGE
:
2323 set_user_handle_info(user
, hi
, 1);
2324 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2325 reply("NSMSG_PASSWORD_CHANGED");
2326 if (nickserv_conf
.sync_log
)
2327 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2330 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2332 * This should only happen if an OREGISTER was sent. Require
2333 * email must be enabled! - SiRVulcaN
2335 if (nickserv_conf
.sync_log
)
2336 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2338 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2339 reply("NSMSG_EMAIL_CHANGED");
2340 if (nickserv_conf
.sync_log
)
2341 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2344 set_user_handle_info(user
, hi
, 1);
2345 reply("NSMSG_AUTH_SUCCESS");
2348 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2349 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2353 nickserv_eat_cookie(hi
->cookie
);
2355 process_adduser_pending(user
);
2360 static NICKSERV_FUNC(cmd_oregnick
) {
2362 struct handle_info
*target
;
2363 struct nick_info
*ni
;
2365 NICKSERV_MIN_PARMS(3);
2366 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2369 if (!is_registerable_nick(nick
)) {
2370 reply("NSMSG_BAD_NICK", nick
);
2373 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2375 reply("NSMSG_NICK_EXISTS", nick
);
2378 register_nick(nick
, target
);
2379 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2383 static NICKSERV_FUNC(cmd_regnick
) {
2385 struct nick_info
*ni
;
2387 if (!is_registerable_nick(user
->nick
)) {
2388 reply("NSMSG_BAD_NICK", user
->nick
);
2391 /* count their nicks, see if it's too many */
2392 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2393 if (n
>= nickserv_conf
.nicks_per_handle
) {
2394 reply("NSMSG_TOO_MANY_NICKS");
2397 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2399 reply("NSMSG_NICK_EXISTS", user
->nick
);
2402 register_nick(user
->nick
, user
->handle_info
);
2403 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2407 static NICKSERV_FUNC(cmd_pass
)
2409 struct handle_info
*hi
;
2410 const char *old_pass
, *new_pass
;
2412 NICKSERV_MIN_PARMS(3);
2413 hi
= user
->handle_info
;
2417 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2418 if (!checkpass(old_pass
, hi
->passwd
)) {
2419 argv
[1] = "BADPASS";
2420 reply("NSMSG_PASSWORD_INVALID");
2423 cryptpass(new_pass
, hi
->passwd
);
2424 if (nickserv_conf
.sync_log
)
2425 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2427 reply("NSMSG_PASS_SUCCESS");
2432 nickserv_addmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2435 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2436 for (i
=0; i
<hi
->masks
->used
; i
++) {
2437 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2438 reply("NSMSG_ADDMASK_ALREADY", new_mask
);
2443 string_list_append(hi
->masks
, new_mask
);
2444 reply("NSMSG_ADDMASK_SUCCESS", new_mask
);
2448 static NICKSERV_FUNC(cmd_addmask
)
2451 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2452 int res
= nickserv_addmask(cmd
, user
, user
->handle_info
, mask
);
2456 if (!is_gline(argv
[1])) {
2457 reply("NSMSG_MASK_INVALID", argv
[1]);
2460 return nickserv_addmask(cmd
, user
, user
->handle_info
, argv
[1]);
2464 static NICKSERV_FUNC(cmd_oaddmask
)
2466 struct handle_info
*hi
;
2468 NICKSERV_MIN_PARMS(3);
2469 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2471 return nickserv_addmask(cmd
, user
, hi
, argv
[2]);
2475 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2478 for (i
=0; i
<hi
->masks
->used
; i
++) {
2479 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2480 char *old_mask
= hi
->masks
->list
[i
];
2481 if (hi
->masks
->used
== 1) {
2482 reply("NSMSG_DELMASK_NOTLAST");
2485 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2486 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2491 reply("NSMSG_DELMASK_NOT_FOUND");
2495 static NICKSERV_FUNC(cmd_delmask
)
2497 NICKSERV_MIN_PARMS(2);
2498 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1]);
2501 static NICKSERV_FUNC(cmd_odelmask
)
2503 struct handle_info
*hi
;
2504 NICKSERV_MIN_PARMS(3);
2505 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2507 return nickserv_delmask(cmd
, user
, hi
, argv
[2]);
2511 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2512 unsigned int nn
, add
= 1, pos
;
2513 unsigned long added
, removed
, flag
;
2515 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2517 case '+': add
= 1; break;
2518 case '-': add
= 0; break;
2520 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2521 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2524 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2525 /* cheesy avoidance of looking up the flag name.. */
2526 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2529 flag
= 1 << (pos
- 1);
2531 added
|= flag
, removed
&= ~flag
;
2533 removed
|= flag
, added
&= ~flag
;
2538 *premoved
= removed
;
2543 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2545 unsigned long before
, after
, added
, removed
;
2546 struct userNode
*uNode
;
2548 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2549 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2551 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2552 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2554 /* Strip helping flag if they're only a support helper and not
2555 * currently in #support. */
2556 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2557 struct channelList
*schannels
;
2559 schannels
= chanserv_support_channels();
2560 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2561 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2562 if (GetUserMode(schannels
->list
[ii
], uNode
))
2564 if (ii
< schannels
->used
)
2568 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2571 if (after
&& !before
) {
2572 /* Add user to current helper list. */
2573 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2574 userList_append(&curr_helpers
, uNode
);
2575 } else if (!after
&& before
) {
2576 /* Remove user from current helper list. */
2577 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2578 userList_remove(&curr_helpers
, uNode
);
2585 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2589 char *set_display
[] = {
2590 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2591 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2592 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2595 reply("NSMSG_SETTING_LIST");
2596 reply("NSMSG_SETTING_LIST_HEADER");
2598 /* Do this so options are presented in a consistent order. */
2599 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2600 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2601 opt(cmd
, user
, hi
, override
, 0, NULL
);
2602 reply("NSMSG_SETTING_LIST_END");
2605 static NICKSERV_FUNC(cmd_set
)
2607 struct handle_info
*hi
;
2610 hi
= user
->handle_info
;
2612 set_list(cmd
, user
, hi
, 0);
2615 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2616 reply("NSMSG_INVALID_OPTION", argv
[1]);
2619 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2622 static NICKSERV_FUNC(cmd_oset
)
2624 struct handle_info
*hi
;
2627 NICKSERV_MIN_PARMS(2);
2629 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2633 set_list(cmd
, user
, hi
, 0);
2637 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2638 reply("NSMSG_INVALID_OPTION", argv
[2]);
2642 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
2645 static OPTION_FUNC(opt_info
)
2649 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2651 hi
->infoline
= NULL
;
2653 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2657 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2658 reply("NSMSG_SET_INFO", info
);
2662 static OPTION_FUNC(opt_width
)
2665 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2667 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2668 hi
->screen_width
= MIN_LINE_SIZE
;
2669 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2670 hi
->screen_width
= MAX_LINE_SIZE
;
2672 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
2676 static OPTION_FUNC(opt_tablewidth
)
2679 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2681 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2682 hi
->table_width
= MIN_LINE_SIZE
;
2683 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2684 hi
->table_width
= MAX_LINE_SIZE
;
2686 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2690 static OPTION_FUNC(opt_color
)
2693 if (enabled_string(argv
[1]))
2694 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2695 else if (disabled_string(argv
[1]))
2696 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2698 reply("MSG_INVALID_BINARY", argv
[1]);
2703 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2707 static OPTION_FUNC(opt_privmsg
)
2710 if (enabled_string(argv
[1]))
2711 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2712 else if (disabled_string(argv
[1]))
2713 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2715 reply("MSG_INVALID_BINARY", argv
[1]);
2720 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2724 static OPTION_FUNC(opt_autohide
)
2727 if (enabled_string(argv
[1]))
2728 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2729 else if (disabled_string(argv
[1]))
2730 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2732 reply("MSG_INVALID_BINARY", argv
[1]);
2737 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2741 static OPTION_FUNC(opt_style
)
2746 if (!irccasecmp(argv
[1], "Clean"))
2747 hi
->userlist_style
= HI_STYLE_CLEAN
;
2748 else if (!irccasecmp(argv
[1], "Advanced"))
2749 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2750 else if (!irccasecmp(argv
[1], "Classic"))
2751 hi
->userlist_style
= HI_STYLE_CLASSIC
;
2752 else /* Default to normal */
2753 hi
->userlist_style
= HI_STYLE_NORMAL
;
2754 } /* TODO: give error if unknow style is chosen */
2756 switch (hi
->userlist_style
) {
2757 case HI_STYLE_ADVANCED
:
2760 case HI_STYLE_CLASSIC
:
2763 case HI_STYLE_CLEAN
:
2766 case HI_STYLE_NORMAL
:
2771 reply("NSMSG_SET_STYLE", style
);
2775 static OPTION_FUNC(opt_announcements
)
2780 if (enabled_string(argv
[1]))
2781 hi
->announcements
= 'y';
2782 else if (disabled_string(argv
[1]))
2783 hi
->announcements
= 'n';
2784 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2785 hi
->announcements
= '?';
2787 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
2792 switch (hi
->announcements
) {
2793 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2794 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2795 case '?': choice
= "default"; break;
2796 default: choice
= "unknown"; break;
2798 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
2802 static OPTION_FUNC(opt_password
)
2805 reply("NSMSG_USE_CMD_PASS");
2810 cryptpass(argv
[1], hi
->passwd
);
2812 if (nickserv_conf
.sync_log
)
2813 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2815 reply("NSMSG_SET_PASSWORD", "***");
2819 static OPTION_FUNC(opt_flags
)
2822 unsigned int ii
, flen
;
2825 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2830 nickserv_apply_flags(user
, hi
, argv
[1]);
2832 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2833 if (hi
->flags
& (1 << ii
))
2834 flags
[flen
++] = handle_flags
[ii
];
2837 reply("NSMSG_SET_FLAGS", flags
);
2839 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2843 static OPTION_FUNC(opt_email
)
2847 if (!valid_email(argv
[1])) {
2848 reply("NSMSG_BAD_EMAIL_ADDR");
2851 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2852 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2855 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2856 reply("NSMSG_EMAIL_SAME");
2858 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2860 nickserv_set_email_addr(hi
, argv
[1]);
2862 nickserv_eat_cookie(hi
->cookie
);
2863 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2866 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2870 static OPTION_FUNC(opt_maxlogins
)
2872 unsigned char maxlogins
;
2874 maxlogins
= strtoul(argv
[1], NULL
, 0);
2875 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2876 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2879 hi
->maxlogins
= maxlogins
;
2881 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2882 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
2886 static OPTION_FUNC(opt_advanced
)
2889 if (enabled_string(argv
[1]))
2890 HANDLE_SET_FLAG(hi
, ADVANCED
);
2891 else if (disabled_string(argv
[1]))
2892 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
2894 reply("MSG_INVALID_BINARY", argv
[1]);
2899 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
2903 static OPTION_FUNC(opt_language
)
2905 struct language
*lang
;
2907 lang
= language_find(argv
[1]);
2908 if (irccasecmp(lang
->name
, argv
[1]))
2909 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2910 hi
->language
= lang
;
2912 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
2917 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2918 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2920 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2921 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2922 && (user
->handle_info
->opserv_level
< 1000))) {
2923 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2926 if ((user
->handle_info
->opserv_level
< new_level
)
2927 || ((user
->handle_info
->opserv_level
== new_level
)
2928 && (user
->handle_info
->opserv_level
< 1000))) {
2929 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2932 if (user
->handle_info
== target
) {
2933 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2936 if (target
->opserv_level
== new_level
)
2938 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2939 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2940 target
->opserv_level
= new_level
;
2944 static OPTION_FUNC(opt_level
)
2949 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2953 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2954 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
2958 static OPTION_FUNC(opt_epithet
)
2960 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2962 struct userNode
*target
, *next_un
;
2965 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
2969 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2973 if ((epithet
[0] == '*') && !epithet
[1])
2976 hi
->epithet
= strdup(epithet
);
2978 for (target
= hi
->users
; target
; target
= next_un
) {
2979 irc_swhois(nickserv
, target
, hi
->epithet
);
2981 next_un
= target
->next_authed
;
2986 reply("NSMSG_SET_EPITHET", hi
->epithet
);
2988 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2992 static OPTION_FUNC(opt_title
)
2998 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
3000 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3005 if(!strcmp(title
, "*")) {
3007 hi
->fakehost
= NULL
;
3010 if (strchr(title
, '.')) {
3011 reply("NSMSG_TITLE_INVALID");
3014 /* Alphanumeric titles only. */
3015 for(sptr
= title
; *sptr
; sptr
++) {
3016 if(!isalnum(*sptr
) && *sptr
!= '-') {
3017 reply("NSMSG_TITLE_INVALID");
3021 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
3022 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3023 reply("NSMSG_TITLE_TRUNCATED");
3027 hi
->fakehost
= malloc(strlen(title
)+2);
3028 hi
->fakehost
[0] = '.';
3029 strcpy(hi
->fakehost
+1, title
);
3032 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3033 title
= hi
->fakehost
+ 1;
3035 /* If theres no title set then the default title will therefore
3036 be the first part of hidden_host in x3.conf, so for
3037 consistency with opt_fakehost we will print this here.
3038 This isnt actually used in P10, its just handled to keep from crashing... */
3039 char *hs
, *hidden_suffix
, *rest
;
3041 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3042 hidden_suffix
= strdup(hs
);
3044 /* Yes we do this twice */
3045 if((rest
= strchr(hidden_suffix
, '.')))
3048 title
= hidden_suffix
;
3052 /* A lame default if someone configured hidden_host to something lame */
3053 title
= strdup("users");
3054 free(hidden_suffix
);
3060 none
= user_find_message(user
, "MSG_NONE");
3061 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3066 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3070 // check for a dot in the vhost
3071 if(strchr(vhost
, '.') == NULL
) {
3072 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3076 // check for a @ in the vhost
3077 if(strchr(vhost
, '@') != NULL
) {
3078 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3082 // check for denied words, inspired by monk at paki.sex
3083 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3084 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3085 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3090 // check for ircu's HOSTLEN length.
3091 if(strlen(vhost
) >= HOSTLEN
) {
3092 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3096 /* This can be handled by the regex now if desired.
3097 if (vhost[strspn(vhost, "0123456789.")]) {
3098 hostname = vhost + strlen(vhost);
3099 for (depth = 1; depth && (hostname > vhost); depth--) {
3101 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3104 if (*hostname == '.') hostname++; * advance past last dot we saw *
3105 if(strlen(hostname) > 4) {
3106 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3111 /* test either regex or as valid handle */
3112 if (nickserv_conf
.valid_fakehost_regex_set
) {
3113 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3116 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3117 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3119 if(err
== REG_NOMATCH
) {
3120 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3129 static OPTION_FUNC(opt_fakehost
)
3133 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3135 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3140 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3141 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3144 if (!strcmp(fake
, "*")) {
3147 hi
->fakehost
= NULL
;
3150 else if (!check_vhost(argv
[1], user
, cmd
)) {
3151 /* check_vhost takes care of error reply */
3157 hi
->fakehost
= strdup(fake
);
3160 fake
= hi
->fakehost
;
3162 fake
= generate_fakehost(hi
);
3164 /* Tell them we set the host */
3166 fake
= user_find_message(user
, "MSG_NONE");
3167 reply("NSMSG_SET_FAKEHOST", fake
);
3171 static OPTION_FUNC(opt_note
)
3174 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3179 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3184 if ((text
[0] == '*') && !text
[1])
3187 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3192 reply("NSMSG_SET_NOTE", hi
->note
? hi
->note
->note
: user_find_message(user
, "MSG_NONE"));
3196 static NICKSERV_FUNC(cmd_reclaim
)
3198 struct handle_info
*hi
;
3199 struct nick_info
*ni
;
3200 struct userNode
*victim
;
3202 NICKSERV_MIN_PARMS(2);
3203 hi
= user
->handle_info
;
3204 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3206 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3209 if (ni
->owner
!= user
->handle_info
) {
3210 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3213 victim
= GetUserH(ni
->nick
);
3215 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3218 if (victim
== user
) {
3219 reply("NSMSG_NICK_USER_YOU");
3222 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3223 switch (nickserv_conf
.reclaim_action
) {
3224 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3225 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3226 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3227 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3232 static NICKSERV_FUNC(cmd_unregnick
)
3235 struct handle_info
*hi
;
3236 struct nick_info
*ni
;
3238 hi
= user
->handle_info
;
3239 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3240 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3242 reply("NSMSG_UNKNOWN_NICK", nick
);
3245 if (hi
!= ni
->owner
) {
3246 reply("NSMSG_NOT_YOUR_NICK", nick
);
3249 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3254 static NICKSERV_FUNC(cmd_ounregnick
)
3256 struct nick_info
*ni
;
3258 NICKSERV_MIN_PARMS(2);
3259 if (!(ni
= get_nick_info(argv
[1]))) {
3260 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3263 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3264 reply("MSG_USER_OUTRANKED", ni
->nick
);
3267 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3272 static NICKSERV_FUNC(cmd_unregister
)
3274 struct handle_info
*hi
;
3277 NICKSERV_MIN_PARMS(2);
3278 hi
= user
->handle_info
;
3281 if (checkpass(passwd
, hi
->passwd
)) {
3282 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3285 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3286 reply("NSMSG_PASSWORD_INVALID");
3291 static NICKSERV_FUNC(cmd_ounregister
)
3293 struct handle_info
*hi
;
3295 NICKSERV_MIN_PARMS(2);
3296 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
3298 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3302 static NICKSERV_FUNC(cmd_status
)
3304 if (nickserv_conf
.disable_nicks
) {
3305 reply("NSMSG_GLOBAL_STATS_NONICK",
3306 dict_size(nickserv_handle_dict
));
3308 if (user
->handle_info
) {
3310 struct nick_info
*ni
;
3311 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3312 reply("NSMSG_HANDLE_STATS", cnt
);
3314 reply("NSMSG_HANDLE_NONE");
3316 reply("NSMSG_GLOBAL_STATS",
3317 dict_size(nickserv_handle_dict
),
3318 dict_size(nickserv_nick_dict
));
3323 static NICKSERV_FUNC(cmd_ghost
)
3325 struct userNode
*target
;
3326 char reason
[MAXLEN
];
3328 NICKSERV_MIN_PARMS(2);
3329 if (!(target
= GetUserH(argv
[1]))) {
3330 reply("MSG_NICK_UNKNOWN", argv
[1]);
3333 if (target
== user
) {
3334 reply("NSMSG_CANNOT_GHOST_SELF");
3337 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3338 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3341 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3342 DelUser(target
, nickserv
, 1, reason
);
3343 reply("NSMSG_GHOST_KILLED", argv
[1]);
3347 static NICKSERV_FUNC(cmd_vacation
)
3349 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3350 reply("NSMSG_ON_VACATION");
3355 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3357 struct handle_info
*hi
;
3360 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3362 saxdb_start_record(ctx
, iter_key(it
), 0);
3363 if (hi
->announcements
!= '?') {
3364 flags
[0] = hi
->announcements
;
3366 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3369 struct handle_cookie
*cookie
= hi
->cookie
;
3372 switch (cookie
->type
) {
3373 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3374 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3375 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3376 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3377 default: type
= NULL
; break;
3380 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3381 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3382 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3384 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3385 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3386 saxdb_end_record(ctx
);
3390 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3392 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3394 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3395 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3396 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3397 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3398 saxdb_end_record(ctx
);
3402 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3406 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3407 if (hi
->flags
& (1 << ii
))
3408 flags
[flen
++] = handle_flags
[ii
];
3410 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3413 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3414 if (hi
->last_quit_host
[0])
3415 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3416 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3417 if (hi
->masks
->used
)
3418 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3419 if (hi
->ignores
->used
)
3420 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3422 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3424 struct string_list
*slist
;
3425 struct nick_info
*ni
;
3427 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3428 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3429 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3433 if (hi
->opserv_level
)
3434 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3435 if (hi
->language
!= lang_C
)
3436 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3437 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3438 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3439 if (hi
->screen_width
)
3440 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3441 if (hi
->table_width
)
3442 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3443 flags
[0] = hi
->userlist_style
;
3445 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3446 saxdb_end_record(ctx
);
3452 static handle_merge_func_t
*handle_merge_func_list
;
3453 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3456 reg_handle_merge_func(handle_merge_func_t func
)
3458 if (handle_merge_func_used
== handle_merge_func_size
) {
3459 if (handle_merge_func_size
) {
3460 handle_merge_func_size
<<= 1;
3461 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3463 handle_merge_func_size
= 8;
3464 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3467 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3470 static NICKSERV_FUNC(cmd_merge
)
3472 struct handle_info
*hi_from
, *hi_to
;
3473 struct userNode
*last_user
;
3474 struct userData
*cList
, *cListNext
;
3475 unsigned int ii
, jj
, n
;
3477 NICKSERV_MIN_PARMS(3);
3479 if (!(hi_from
= get_victim_oper(cmd
, user
, argv
[1])))
3481 if (!(hi_to
= get_victim_oper(cmd
, user
, argv
[2])))
3483 if (hi_to
== hi_from
) {
3484 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3488 for (n
=0; n
<handle_merge_func_used
; n
++)
3489 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3491 /* Append "from" handle's nicks to "to" handle's nick list. */
3493 struct nick_info
*last_ni
;
3494 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3495 last_ni
->next
= hi_from
->nicks
;
3497 while (hi_from
->nicks
) {
3498 hi_from
->nicks
->owner
= hi_to
;
3499 hi_from
->nicks
= hi_from
->nicks
->next
;
3502 /* Merge the hostmasks. */
3503 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3504 char *mask
= hi_from
->masks
->list
[ii
];
3505 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3506 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3508 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3509 string_list_append(hi_to
->masks
, strdup(mask
));
3512 /* Merge the ignores. */
3513 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3514 char *ignore
= hi_from
->ignores
->list
[ii
];
3515 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3516 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3518 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3519 string_list_append(hi_to
->ignores
, strdup(ignore
));
3522 /* Merge the lists of authed users. */
3524 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3525 last_user
->next_authed
= hi_from
->users
;
3527 hi_to
->users
= hi_from
->users
;
3529 /* Repoint the old "from" handle's users. */
3530 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3531 last_user
->handle_info
= hi_to
;
3533 hi_from
->users
= NULL
;
3535 /* Merge channel userlists. */
3536 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3537 struct userData
*cList2
;
3538 cListNext
= cList
->u_next
;
3539 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3540 if (cList
->channel
== cList2
->channel
)
3542 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3543 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
);
3544 /* keep cList2 in hi_to; remove cList from hi_from */
3545 del_channel_user(cList
, 1);
3548 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
);
3549 /* remove the lower-ranking cList2 from hi_to */
3550 del_channel_user(cList2
, 1);
3552 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3554 /* cList needs to be moved from hi_from to hi_to */
3555 cList
->handle
= hi_to
;
3556 /* Remove from linked list for hi_from */
3557 assert(!cList
->u_prev
);
3558 hi_from
->channels
= cList
->u_next
;
3560 cList
->u_next
->u_prev
= cList
->u_prev
;
3561 /* Add to linked list for hi_to */
3562 cList
->u_prev
= NULL
;
3563 cList
->u_next
= hi_to
->channels
;
3564 if (hi_to
->channels
)
3565 hi_to
->channels
->u_prev
= cList
;
3566 hi_to
->channels
= cList
;
3570 /* Do they get an OpServ level promotion? */
3571 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3572 hi_to
->opserv_level
= hi_from
->opserv_level
;
3574 /* What about last seen time? */
3575 if (hi_from
->lastseen
> hi_to
->lastseen
)
3576 hi_to
->lastseen
= hi_from
->lastseen
;
3578 /* Does a fakehost carry over? (This intentionally doesn't set it
3579 * for users previously attached to hi_to. They'll just have to
3582 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3583 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3585 /* Notify of success. */
3586 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3587 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
3588 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3590 /* Unregister the "from" handle. */
3591 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3596 struct nickserv_discrim
{
3597 unsigned int limit
, min_level
, max_level
;
3598 unsigned long flags_on
, flags_off
;
3599 time_t min_registered
, max_registered
;
3601 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3602 const char *nickmask
;
3603 const char *hostmask
;
3604 const char *handlemask
;
3605 const char *emailmask
;
3608 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3610 struct discrim_apply_info
{
3611 struct nickserv_discrim
*discrim
;
3612 discrim_search_func func
;
3613 struct userNode
*source
;
3614 unsigned int matched
;
3617 static struct nickserv_discrim
*
3618 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
3621 struct nickserv_discrim
*discrim
;
3623 discrim
= malloc(sizeof(*discrim
));
3624 memset(discrim
, 0, sizeof(*discrim
));
3625 discrim
->min_level
= 0;
3626 discrim
->max_level
= ~0;
3627 discrim
->limit
= 50;
3628 discrim
->min_registered
= 0;
3629 discrim
->max_registered
= INT_MAX
;
3630 discrim
->lastseen
= now
;
3632 for (i
=0; i
<argc
; i
++) {
3633 if (i
== argc
- 1) {
3634 reply("MSG_MISSING_PARAMS", argv
[i
]);
3637 if (!irccasecmp(argv
[i
], "limit")) {
3638 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3639 } else if (!irccasecmp(argv
[i
], "flags")) {
3640 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3641 } else if (!irccasecmp(argv
[i
], "registered")) {
3642 const char *cmp
= argv
[++i
];
3643 if (cmp
[0] == '<') {
3644 if (cmp
[1] == '=') {
3645 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3647 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3649 } else if (cmp
[0] == '=') {
3650 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3651 } else if (cmp
[0] == '>') {
3652 if (cmp
[1] == '=') {
3653 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3655 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3658 reply("MSG_INVALID_CRITERIA", cmp
);
3660 } else if (!irccasecmp(argv
[i
], "seen")) {
3661 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3662 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3663 discrim
->nickmask
= argv
[++i
];
3664 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3666 if (!irccasecmp(argv
[i
], "exact")) {
3667 if (i
== argc
- 1) {
3668 reply("MSG_MISSING_PARAMS", argv
[i
]);
3671 discrim
->hostmask_type
= EXACT
;
3672 } else if (!irccasecmp(argv
[i
], "subset")) {
3673 if (i
== argc
- 1) {
3674 reply("MSG_MISSING_PARAMS", argv
[i
]);
3677 discrim
->hostmask_type
= SUBSET
;
3678 } else if (!irccasecmp(argv
[i
], "superset")) {
3679 if (i
== argc
- 1) {
3680 reply("MSG_MISSING_PARAMS", argv
[i
]);
3683 discrim
->hostmask_type
= SUPERSET
;
3684 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3685 if (i
== argc
- 1) {
3686 reply("MSG_MISSING_PARAMS", argv
[i
]);
3689 discrim
->hostmask_type
= LASTQUIT
;
3692 discrim
->hostmask_type
= SUPERSET
;
3694 discrim
->hostmask
= argv
[++i
];
3695 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3696 if (!irccasecmp(argv
[++i
], "*")) {
3697 discrim
->handlemask
= 0;
3699 discrim
->handlemask
= argv
[i
];
3701 } else if (!irccasecmp(argv
[i
], "email")) {
3702 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3703 reply("MSG_NO_SEARCH_ACCESS", "email");
3705 } else if (!irccasecmp(argv
[++i
], "*")) {
3706 discrim
->emailmask
= 0;
3708 discrim
->emailmask
= argv
[i
];
3710 } else if (!irccasecmp(argv
[i
], "access")) {
3711 const char *cmp
= argv
[++i
];
3712 if (cmp
[0] == '<') {
3713 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3714 if (cmp
[1] == '=') {
3715 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3717 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3719 } else if (cmp
[0] == '=') {
3720 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3721 } else if (cmp
[0] == '>') {
3722 if (cmp
[1] == '=') {
3723 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3725 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3728 reply("MSG_INVALID_CRITERIA", cmp
);
3731 reply("MSG_INVALID_CRITERIA", argv
[i
]);
3742 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3744 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3745 || (discrim
->flags_off
& hi
->flags
)
3746 || (discrim
->min_registered
> hi
->registered
)
3747 || (discrim
->max_registered
< hi
->registered
)
3748 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3749 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3750 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3751 || (discrim
->min_level
> hi
->opserv_level
)
3752 || (discrim
->max_level
< hi
->opserv_level
)) {
3755 if (discrim
->hostmask
) {
3757 for (i
=0; i
<hi
->masks
->used
; i
++) {
3758 const char *mask
= hi
->masks
->list
[i
];
3759 if ((discrim
->hostmask_type
== SUBSET
)
3760 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3761 else if ((discrim
->hostmask_type
== EXACT
)
3762 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3763 else if ((discrim
->hostmask_type
== SUPERSET
)
3764 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3765 else if ((discrim
->hostmask_type
== LASTQUIT
)
3766 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3768 if (i
==hi
->masks
->used
) return 0;
3770 if (discrim
->nickmask
) {
3771 struct nick_info
*nick
= hi
->nicks
;
3773 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3776 if (!nick
) return 0;
3782 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3784 dict_iterator_t it
, next
;
3785 unsigned int matched
;
3787 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3788 it
&& (matched
< discrim
->limit
);
3790 next
= iter_next(it
);
3791 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3792 dsf(source
, iter_data(it
));
3800 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3802 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3806 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3811 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3813 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3814 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3818 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3820 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3821 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3822 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3823 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3824 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3828 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3830 struct handle_info_list hil
;
3831 struct helpfile_table tbl
;
3836 memset(&hil
, 0, sizeof(hil
));
3837 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3838 struct handle_info
*hi
= iter_data(it
);
3839 if (hi
->opserv_level
)
3840 handle_info_list_append(&hil
, hi
);
3842 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3843 tbl
.length
= hil
.used
+ 1;
3845 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
3846 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3847 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3850 for (ii
= 0; ii
< hil
.used
; ) {
3851 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3852 ary
[0] = hil
.list
[ii
]->handle
;
3853 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3854 tbl
.contents
[++ii
] = ary
;
3856 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3857 /*reply("MSG_MATCH_COUNT", hil.used); */
3858 for (ii
= 0; ii
< hil
.used
; ii
++)
3859 free(tbl
.contents
[ii
]);
3864 static NICKSERV_FUNC(cmd_search
)
3866 struct nickserv_discrim
*discrim
;
3867 discrim_search_func action
;
3868 struct svccmd
*subcmd
;
3869 unsigned int matches
;
3872 NICKSERV_MIN_PARMS(3);
3873 sprintf(buf
, "search %s", argv
[1]);
3874 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3875 if (!irccasecmp(argv
[1], "print"))
3876 action
= search_print_func
;
3877 else if (!irccasecmp(argv
[1], "count"))
3878 action
= search_count_func
;
3879 else if (!irccasecmp(argv
[1], "unregister"))
3880 action
= search_unregister_func
;
3882 reply("NSMSG_INVALID_ACTION", argv
[1]);
3886 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3889 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
3893 if (action
== search_print_func
)
3894 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3895 else if (action
== search_count_func
)
3896 discrim
->limit
= INT_MAX
;
3898 matches
= nickserv_discrim_search(discrim
, action
, user
);
3901 reply("MSG_MATCH_COUNT", matches
);
3903 reply("MSG_NO_MATCHES");
3909 static MODCMD_FUNC(cmd_checkpass
)
3911 struct handle_info
*hi
;
3913 NICKSERV_MIN_PARMS(3);
3914 if (!(hi
= get_handle_info(argv
[1]))) {
3915 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3918 if (checkpass(argv
[2], hi
->passwd
))
3919 reply("CHECKPASS_YES");
3921 reply("CHECKPASS_NO");
3927 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3930 struct string_list
*masks
, *slist
, *ignores
;
3931 struct handle_info
*hi
;
3932 struct userNode
*authed_users
;
3933 struct userData
*channels
;
3934 unsigned long int id
;
3937 char *setter
, *note
;
3940 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3941 id
= str
? strtoul(str
, NULL
, 0) : 0;
3942 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3944 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3947 if ((hi
= get_handle_info(handle
))) {
3948 authed_users
= hi
->users
;
3949 channels
= hi
->channels
;
3951 hi
->channels
= NULL
;
3952 dict_remove(nickserv_handle_dict
, hi
->handle
);
3954 authed_users
= NULL
;
3957 hi
= register_handle(handle
, str
, id
);
3959 hi
->users
= authed_users
;
3960 while (authed_users
) {
3961 authed_users
->handle_info
= hi
;
3962 authed_users
= authed_users
->next_authed
;
3965 hi
->channels
= channels
;
3966 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3967 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3968 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
3969 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
3970 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3971 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3972 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3973 hi
->language
= language_find(str
? str
: "C");
3974 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3975 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3976 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3978 hi
->infoline
= strdup(str
);
3979 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3980 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3981 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3982 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3983 /* We want to read the nicks even if disable_nicks is set. This is so
3984 * that we don't lose the nick data entirely. */
3985 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3987 for (ii
=0; ii
<slist
->used
; ii
++)
3988 register_nick(slist
->list
[ii
], hi
);
3990 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3992 for (ii
=0; str
[ii
]; ii
++)
3993 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3995 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3996 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3997 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3998 hi
->announcements
= str
? str
[0] : '?';
3999 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
4000 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
4001 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
4002 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
4003 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
4005 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
4007 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
4008 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
4010 nickserv_set_email_addr(hi
, str
);
4011 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
4013 hi
->epithet
= strdup(str
);
4014 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
4016 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
4017 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
4018 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4019 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
4020 if (setter
&& date
&& note
)
4022 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
4027 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
4029 hi
->fakehost
= strdup(str
);
4031 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4033 const char *data
, *type
, *expires
, *cookie_str
;
4034 struct handle_cookie
*cookie
;
4036 cookie
= calloc(1, sizeof(*cookie
));
4037 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4038 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4039 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4040 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4041 if (!type
|| !expires
|| !cookie_str
) {
4042 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4045 if (!irccasecmp(type
, KEY_ACTIVATION
))
4046 cookie
->type
= ACTIVATION
;
4047 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4048 cookie
->type
= PASSWORD_CHANGE
;
4049 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4050 cookie
->type
= EMAIL_CHANGE
;
4051 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4052 cookie
->type
= ALLOWAUTH
;
4054 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4057 cookie
->expires
= strtoul(expires
, NULL
, 0);
4058 if (cookie
->expires
< now
)
4061 cookie
->data
= strdup(data
);
4062 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4066 nickserv_bake_cookie(cookie
);
4068 nickserv_free_cookie(cookie
);
4073 nickserv_saxdb_read(dict_t db
) {
4075 struct record_data
*rd
;
4077 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4079 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
4084 static NICKSERV_FUNC(cmd_mergedb
)
4086 struct timeval start
, stop
;
4089 NICKSERV_MIN_PARMS(2);
4090 gettimeofday(&start
, NULL
);
4091 if (!(db
= parse_database(argv
[1]))) {
4092 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4095 nickserv_saxdb_read(db
);
4097 gettimeofday(&stop
, NULL
);
4098 stop
.tv_sec
-= start
.tv_sec
;
4099 stop
.tv_usec
-= start
.tv_usec
;
4100 if (stop
.tv_usec
< 0) {
4102 stop
.tv_usec
+= 1000000;
4104 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4109 expire_handles(UNUSED_ARG(void *data
))
4111 dict_iterator_t it
, next
;
4113 struct handle_info
*hi
;
4115 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4116 next
= iter_next(it
);
4118 if ((hi
->opserv_level
> 0)
4120 || HANDLE_FLAGGED(hi
, FROZEN
)
4121 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4124 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4125 if ((now
- hi
->lastseen
) > expiry
) {
4126 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4127 nickserv_unregister_handle(hi
, NULL
, NULL
);
4131 if (nickserv_conf
.handle_expire_frequency
)
4132 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4136 nickserv_load_dict(const char *fname
)
4140 if (!(file
= fopen(fname
, "r"))) {
4141 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4144 while (!feof(file
)) {
4145 fgets(line
, sizeof(line
), file
);
4148 if (line
[strlen(line
)-1] == '\n')
4149 line
[strlen(line
)-1] = 0;
4150 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4153 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4156 static enum reclaim_action
4157 reclaim_action_from_string(const char *str
) {
4159 return RECLAIM_NONE
;
4160 else if (!irccasecmp(str
, "warn"))
4161 return RECLAIM_WARN
;
4162 else if (!irccasecmp(str
, "svsnick"))
4163 return RECLAIM_SVSNICK
;
4164 else if (!irccasecmp(str
, "kill"))
4165 return RECLAIM_KILL
;
4167 return RECLAIM_NONE
;
4171 nickserv_conf_read(void)
4173 dict_t conf_node
, child
;
4176 struct string_list
*strlist
;
4178 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4179 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4182 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4184 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4185 if (nickserv_conf
.valid_handle_regex_set
)
4186 regfree(&nickserv_conf
.valid_handle_regex
);
4188 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4189 nickserv_conf
.valid_handle_regex_set
= !err
;
4190 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4192 nickserv_conf
.valid_handle_regex_set
= 0;
4194 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4195 if (nickserv_conf
.valid_nick_regex_set
)
4196 regfree(&nickserv_conf
.valid_nick_regex
);
4198 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4199 nickserv_conf
.valid_nick_regex_set
= !err
;
4200 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4202 nickserv_conf
.valid_nick_regex_set
= 0;
4204 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4205 if (nickserv_conf
.valid_fakehost_regex_set
)
4206 regfree(&nickserv_conf
.valid_fakehost_regex
);
4208 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4209 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4210 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4212 nickserv_conf
.valid_fakehost_regex_set
= 0;
4214 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4216 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4217 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4218 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4219 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4220 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4221 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4222 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4223 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4224 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4225 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4226 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4227 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4228 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4229 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4230 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4231 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4232 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4233 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4234 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4235 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4236 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4237 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4238 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4239 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4240 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4242 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4243 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4244 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4246 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4247 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4248 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4250 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4251 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4252 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4253 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4254 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4255 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4256 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4257 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4258 if (!nickserv_conf
.disable_nicks
) {
4259 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4260 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4261 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4262 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4263 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4264 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4265 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4266 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4268 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4269 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4270 const char *key
= iter_key(it
), *value
;
4274 if (!strncasecmp(key
, "uc_", 3))
4275 flag
= toupper(key
[3]);
4276 else if (!strncasecmp(key
, "lc_", 3))
4277 flag
= tolower(key
[3]);
4281 if ((pos
= handle_inverse_flags
[flag
])) {
4282 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4283 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4286 if (nickserv_conf
.weak_password_dict
)
4287 dict_delete(nickserv_conf
.weak_password_dict
);
4288 nickserv_conf
.weak_password_dict
= dict_new();
4289 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4290 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4291 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4292 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4294 nickserv_load_dict(str
);
4295 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4296 if (nickserv
&& str
)
4297 NickChange(nickserv
, str
, 0);
4298 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4299 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4300 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4301 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4302 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4303 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4304 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4305 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4306 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4307 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4308 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4309 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4310 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4311 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4312 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4313 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4314 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4315 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4316 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4317 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4319 free_string_list(nickserv_conf
.denied_fakehost_words
);
4320 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4322 strlist
= string_list_copy(strlist
);
4324 strlist
= alloc_string_list(4);
4325 string_list_append(strlist
, strdup("sex"));
4326 string_list_append(strlist
, strdup("fuck"));
4328 nickserv_conf
.denied_fakehost_words
= strlist
;
4330 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4331 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4333 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4334 nickserv_conf
.auto_oper
= str
? str
: "";
4336 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4337 nickserv_conf
.auto_admin
= str
? str
: "";
4339 str
= conf_get_data("server/network", RECDB_QSTRING
);
4340 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4341 if (!nickserv_conf
.auth_policer_params
) {
4342 nickserv_conf
.auth_policer_params
= policer_params_new();
4343 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4344 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4346 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4347 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4348 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4350 str
= database_get_data(conf_node
, KEY_LDAP_ENABLE
, RECDB_QSTRING
);
4351 nickserv_conf
.ldap_enable
= str
? strtoul(str
, NULL
, 0) : 0;
4353 if(nickserv_conf
.ldap_enable
> 0) {
4354 /* ldap is enabled but not compiled in - error out */
4355 log_module(MAIN_LOG
, LOG_ERROR
, "ldap is enabled in config, but not compiled in!");
4356 nickserv_conf
.ldap_enable
= 0;
4362 str
= database_get_data(conf_node
, KEY_LDAP_HOST
, RECDB_QSTRING
);
4363 nickserv_conf
.ldap_host
= str
? str
: "";
4365 str
= database_get_data(conf_node
, KEY_LDAP_PORT
, RECDB_QSTRING
);
4366 nickserv_conf
.ldap_port
= str
? strtoul(str
, NULL
, 0) : LDAP_PORT
;
4368 str
= database_get_data(conf_node
, KEY_LDAP_BASE
, RECDB_QSTRING
);
4369 nickserv_conf
.ldap_base
= str
? str
: "";
4371 str
= database_get_data(conf_node
, KEY_LDAP_DN_FMT
, RECDB_QSTRING
);
4372 nickserv_conf
.ldap_dn_fmt
= str
? str
: "";
4374 str
= database_get_data(conf_node
, KEY_LDAP_VERSION
, RECDB_QSTRING
);
4375 nickserv_conf
.ldap_version
= str
? strtoul(str
, NULL
, 0) : 3;
4377 str
= database_get_data(conf_node
, KEY_LDAP_AUTOCREATE
, RECDB_QSTRING
);
4378 nickserv_conf
.ldap_autocreate
= str
? strtoul(str
, NULL
, 0) : 0;
4380 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_DN
, RECDB_QSTRING
);
4381 nickserv_conf
.ldap_admin_dn
= str
? str
: "";
4383 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_PASS
, RECDB_QSTRING
);
4384 nickserv_conf
.ldap_admin_pass
= str
? str
: "";
4386 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_ACCOUNT
, RECDB_QSTRING
);
4387 nickserv_conf
.ldap_field_account
= str
? str
: "";
4389 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_PASSWORD
, RECDB_QSTRING
);
4390 nickserv_conf
.ldap_field_password
= str
? str
: "";
4392 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_EMAIL
, RECDB_QSTRING
);
4393 nickserv_conf
.ldap_field_email
= str
? str
: "";
4400 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4402 char newnick
[NICKLEN
+1];
4411 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4413 case RECLAIM_SVSNICK
:
4415 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4416 } while (GetUserH(newnick
));
4417 irc_svsnick(nickserv
, user
, newnick
);
4420 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4421 irc_kill(nickserv
, user
, msg
);
4427 nickserv_reclaim_p(void *data
) {
4428 struct userNode
*user
= data
;
4429 struct nick_info
*ni
= get_nick_info(user
->nick
);
4431 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4435 check_user_nick(struct userNode
*user
) {
4436 struct nick_info
*ni
;
4437 user
->modes
&= ~FLAGS_REGNICK
;
4438 if (!(ni
= get_nick_info(user
->nick
)))
4440 if (user
->handle_info
== ni
->owner
) {
4441 user
->modes
|= FLAGS_REGNICK
;
4445 if (nickserv_conf
.warn_nick_owned
)
4446 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4447 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4449 if (nickserv_conf
.auto_reclaim_delay
)
4450 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4452 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4457 handle_new_user(struct userNode
*user
)
4459 return check_user_nick(user
);
4463 handle_account(struct userNode
*user
, const char *stamp
)
4465 struct handle_info
*hi
;
4468 #ifdef WITH_PROTOCOL_P10
4469 time_t timestamp
= 0;
4471 colon
= strchr(stamp
, ':');
4472 if(colon
&& colon
[1])
4475 timestamp
= atoi(colon
+1);
4477 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4478 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4480 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
);
4484 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4485 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4489 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4492 set_user_handle_info(user
, hi
, 0);
4494 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4499 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4501 struct handle_info
*hi
;
4503 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4504 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4505 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4507 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4508 check_user_nick(user
);
4512 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4514 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4515 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4516 set_user_handle_info(user
, NULL
, 0);
4519 static struct modcmd
*
4520 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4522 if (min_level
> 0) {
4524 sprintf(buf
, "%u", min_level
);
4525 if (must_be_qualified
) {
4526 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4528 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4530 } else if (min_level
== 0) {
4531 if (must_be_qualified
) {
4532 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4534 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4537 if (must_be_qualified
) {
4538 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4540 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4546 nickserv_db_cleanup(void)
4548 unreg_del_user_func(nickserv_remove_user
);
4549 userList_clean(&curr_helpers
);
4550 policer_params_delete(nickserv_conf
.auth_policer_params
);
4551 dict_delete(nickserv_handle_dict
);
4552 dict_delete(nickserv_nick_dict
);
4553 dict_delete(nickserv_opt_dict
);
4554 dict_delete(nickserv_allow_auth_dict
);
4555 dict_delete(nickserv_email_dict
);
4556 dict_delete(nickserv_id_dict
);
4557 dict_delete(nickserv_conf
.weak_password_dict
);
4558 free(auth_func_list
);
4559 free(unreg_func_list
);
4561 free(allowauth_func_list
);
4562 free(handle_merge_func_list
);
4563 free(failpw_func_list
);
4564 if (nickserv_conf
.valid_handle_regex_set
)
4565 regfree(&nickserv_conf
.valid_handle_regex
);
4566 if (nickserv_conf
.valid_nick_regex_set
)
4567 regfree(&nickserv_conf
.valid_nick_regex
);
4571 init_nickserv(const char *nick
)
4573 struct chanNode
*chan
;
4575 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4576 reg_new_user_func(handle_new_user
);
4577 reg_nick_change_func(handle_nick_change
);
4578 reg_del_user_func(nickserv_remove_user
);
4579 reg_account_func(handle_account
);
4581 /* set up handle_inverse_flags */
4582 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4583 for (i
=0; handle_flags
[i
]; i
++) {
4584 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4585 flag_access_levels
[i
] = 0;
4588 conf_register_reload(nickserv_conf_read
);
4589 nickserv_opt_dict
= dict_new();
4590 nickserv_email_dict
= dict_new();
4592 dict_set_free_keys(nickserv_email_dict
, free
);
4593 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4595 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4596 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4597 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4598 * a big pain to disable since its nolonger in the config file. ) -Rubin
4600 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4601 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4602 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4603 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4604 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4605 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4606 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4607 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4608 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4609 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4610 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4611 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4612 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4613 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4614 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4615 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4616 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4617 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4618 if (!nickserv_conf
.disable_nicks
) {
4619 /* nick management commands */
4620 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4621 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4622 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4623 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4624 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4625 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4627 if (nickserv_conf
.email_enabled
) {
4628 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4629 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4630 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4631 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4632 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4633 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4635 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4636 /* ignore commands */
4637 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
4638 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
4639 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
4640 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
4641 /* miscellaneous commands */
4642 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4643 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4644 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4645 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4646 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4648 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4649 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4650 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4651 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4652 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4653 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4654 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4655 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4656 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4657 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4658 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4659 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4660 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4661 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4662 if (nickserv_conf
.titlehost_suffix
) {
4663 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4664 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4666 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4667 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4668 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
4669 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4671 nickserv_handle_dict
= dict_new();
4672 dict_set_free_keys(nickserv_handle_dict
, free
);
4673 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4675 nickserv_id_dict
= dict_new();
4676 dict_set_free_keys(nickserv_id_dict
, free
);
4678 nickserv_nick_dict
= dict_new();
4679 dict_set_free_data(nickserv_nick_dict
, free
);
4681 nickserv_allow_auth_dict
= dict_new();
4683 userList_init(&curr_helpers
);
4686 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4687 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4688 nickserv_service
= service_register(nickserv
);
4690 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4691 reg_exit_func(nickserv_db_cleanup
);
4692 if(nickserv_conf
.handle_expire_frequency
)
4693 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4695 if(autojoin_channels
&& nickserv
) {
4696 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
4697 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
4698 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
4702 ldap_do_init(nickserv_conf
);
4705 message_register_table(msgtab
);