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 3 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>
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"
82 #define KEY_OUNREGISTER_INACTIVE "ounregister_inactive"
83 #define KEY_OUNREGISTER_FLAGS "ounregister_flags"
86 #define KEY_PASSWD "passwd"
87 #define KEY_NICKS "nicks"
88 #define KEY_MASKS "masks"
89 #define KEY_IGNORES "ignores"
90 #define KEY_OPSERV_LEVEL "opserv_level"
91 #define KEY_FLAGS "flags"
92 #define KEY_REGISTER_ON "register"
93 #define KEY_LAST_SEEN "lastseen"
94 #define KEY_INFO "info"
95 #define KEY_USERLIST_STYLE "user_style"
96 #define KEY_SCREEN_WIDTH "screen_width"
97 #define KEY_LAST_AUTHED_HOST "last_authed_host"
98 #define KEY_LAST_QUIT_HOST "last_quit_host"
99 #define KEY_EMAIL_ADDR "email_addr"
100 #define KEY_COOKIE "cookie"
101 #define KEY_COOKIE_DATA "data"
102 #define KEY_COOKIE_TYPE "type"
103 #define KEY_COOKIE_EXPIRES "expires"
104 #define KEY_ACTIVATION "activation"
105 #define KEY_PASSWORD_CHANGE "password change"
106 #define KEY_EMAIL_CHANGE "email change"
107 #define KEY_ALLOWAUTH "allowauth"
108 #define KEY_EPITHET "epithet"
109 #define KEY_TABLE_WIDTH "table_width"
110 #define KEY_ANNOUNCEMENTS "announcements"
111 #define KEY_MAXLOGINS "maxlogins"
112 #define KEY_FAKEHOST "fakehost"
113 #define KEY_NOTE_NOTE "note"
114 #define KEY_NOTE_SETTER "setter"
115 #define KEY_NOTE_DATE "date"
116 #define KEY_KARMA "karma"
117 #define KEY_FORCE_HANDLES_LOWERCASE "force_handles_lowercase"
119 #define KEY_LDAP_ENABLE "ldap_enable"
122 #define KEY_LDAP_URI "ldap_uri"
123 #define KEY_LDAP_BASE "ldap_base"
124 #define KEY_LDAP_DN_FMT "ldap_dn_fmt"
125 #define KEY_LDAP_VERSION "ldap_version"
126 #define KEY_LDAP_AUTOCREATE "ldap_autocreate"
127 #define KEY_LDAP_ADMIN_DN "ldap_admin_dn"
128 #define KEY_LDAP_ADMIN_PASS "ldap_admin_pass"
129 #define KEY_LDAP_FIELD_ACCOUNT "ldap_field_account"
130 #define KEY_LDAP_FIELD_PASSWORD "ldap_field_password"
131 #define KEY_LDAP_FIELD_EMAIL "ldap_field_email"
132 #define KEY_LDAP_OBJECT_CLASSES "ldap_object_classes"
133 #define KEY_LDAP_OPER_GROUP_DN "ldap_oper_group_dn"
134 #define KEY_LDAP_OPER_GROUP_LEVEL "ldap_oper_group_level"
135 #define KEY_LDAP_FIELD_GROUP_MEMBER "ldap_field_group_member"
136 #define KEY_LDAP_TIMEOUT "ldap_timeout"
139 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
141 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
142 #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[])
143 typedef OPTION_FUNC(option_func_t
);
145 DEFINE_LIST(handle_info_list
, struct handle_info
*)
147 #define NICKSERV_MIN_PARMS(N) do { \
149 reply("MSG_MISSING_PARAMS", argv[0]); \
150 svccmd_send_help_brief(user, nickserv, cmd); \
154 struct userNode
*nickserv
;
155 struct userList curr_helpers
;
156 const char *handle_flags
= HANDLE_FLAGS
;
158 extern struct string_list
*autojoin_channels
;
159 static struct module *nickserv_module
;
160 static struct service
*nickserv_service
;
161 static struct log_type
*NS_LOG
;
162 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
163 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
164 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
165 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
166 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
167 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
168 static char handle_inverse_flags
[256];
169 static unsigned int flag_access_levels
[32];
170 static const struct message_entry msgtab
[] = {
171 { "NSMSG_NO_ANGLEBRACKETS", "The < and > in help indicate that that word is a required parameter, but DO NOT actually type them in messages to me." },
172 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
173 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu characters or less."},
174 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
175 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
176 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
177 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
178 { "NSMSG_LDAP_FAIL", "There was a problem in contacting the account server (ldap): %s. Please try again later." },
179 { "NSMSG_LDAP_FAIL_ADD", "There was a problem in adding account %s to ldap: %s." },
180 { "NSMSG_LDAP_FAIL_SEND_EMAIL", "There was a problem in storing your email address in the account server (ldap): %s. Please try again later." },
181 { "NSMSG_LDAP_FAIL_GET_EMAIL", "There was a problem in retrieving your email address from the account server (ldap): %s. Please try again later." },
182 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
183 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
184 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
185 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
186 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
187 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
188 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
189 { "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." },
190 { "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." },
191 { "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." },
192 { "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." },
193 { "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." },
194 { "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." },
195 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
196 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
197 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
198 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
199 { "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." },
200 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
201 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
202 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
203 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
204 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
205 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
206 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
207 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
208 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
209 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
210 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
211 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
212 { "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 *@*)." },
213 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
214 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
215 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
216 { "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)" },
217 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
218 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
219 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
220 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
221 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
222 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
223 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
224 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
225 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
226 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
227 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
228 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
229 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
230 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
231 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
232 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
233 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
234 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
235 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
236 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
237 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
238 { "NSMSG_HANDLEINFO_KARMA", " Karma: %d" },
239 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
240 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
241 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
242 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
243 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
244 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
245 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
246 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
247 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
248 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
249 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
250 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
251 { "NSMSG_INVALID_KARMA", "$b%s$b is not a valid karma modifier." },
252 { "NSMSG_SET_KARMA", "$bKARMA: $b%d$b" },
253 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
254 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
255 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
256 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
257 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
258 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
259 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
260 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
261 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
262 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
263 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
264 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
265 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
266 { "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)." },
267 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
268 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
269 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
270 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
271 { "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." },
272 { "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." },
273 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
274 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
275 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
276 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
277 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
278 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
279 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
280 { "NSMSG_PASS_SUCCESS", "Password changed." },
281 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
282 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
283 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
284 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
285 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
286 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
287 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
288 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
289 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
290 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
291 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
292 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
293 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
294 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
295 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
296 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
297 { "NSMSG_UNREGISTER_MUST_FORCE", "Account $b%s$b is not inactive or has special flags set; use FORCE to unregister it." },
298 { "NSMSG_UNREGISTER_CANNOT_FORCE", "Account $b%s$b is not inactive or has special flags set; have an IRCOp use FORCE to unregister it." },
299 { "NSMSG_UNREGISTER_NODELETE", "Account $b%s$b is protected from unregistration." },
300 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
301 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
302 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
303 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
304 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
305 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
306 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
307 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
308 { "NSMSG_NO_ACCESS", "Access denied." },
309 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
310 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
311 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
312 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
313 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
314 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
315 { "NSMSG_BAD_HANDLE", "Account $b%s$b is not allowed because it is reserved, is too long, or contains invalid characters." },
316 { "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." },
317 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
318 { "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." },
319 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
320 { "NSMSG_SEARCH_MATCH", "Match: %s" },
321 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
322 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
323 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
324 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
325 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
326 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
327 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
328 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
329 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
330 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
331 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
332 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
333 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
334 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
335 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
336 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
337 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
338 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
339 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
340 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
341 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
342 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
343 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
344 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
345 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
346 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
347 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
348 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
349 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
350 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
351 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
352 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
353 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
354 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
356 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
357 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
359 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
360 { "NSEMAIL_ACTIVATION_BODY",
361 "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"
363 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
364 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
365 "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"
366 "/msg %3$s@%4$s AUTH %5$s your-password\n"
367 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
368 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
370 "If you did NOT request this account, you do not need to do anything.\n"
371 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
372 { "NSEMAIL_ACTIVATION_BODY_WEB",
373 "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"
375 "To verify your email address and complete the account registration, visit the following URL:\n"
376 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
378 "If you did NOT request this account, you do not need to do anything.\n"
379 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
380 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
381 { "NSEMAIL_PASSWORD_CHANGE_BODY",
382 "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"
383 "To complete the password change, log on to %1$s and type the following command:\n"
384 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
385 "If you did NOT request your password to be changed, you do not need to do anything.\n"
386 "Please contact the %1$s staff if you have questions." },
387 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
388 "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"
389 "To complete the password change, click the following URL:\n"
390 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
391 "If you did NOT request your password to be changed, you do not need to do anything.\n"
392 "Please contact the %1$s staff if you have questions." },
393 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
394 #ifdef stupid_verify_old_email
395 { "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." },
396 { "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." },
398 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
399 { "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." },
400 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
401 { "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." },
402 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
403 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
404 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
405 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
406 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
407 { "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." },
408 { "CHECKPASS_YES", "Yes." },
409 { "CHECKPASS_NO", "No." },
410 { "CHECKEMAIL_NOT_SET", "No email set." },
411 { "CHECKEMAIL_YES", "Yes." },
412 { "CHECKEMAIL_NO", "No." },
413 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
417 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
418 static void nickserv_reclaim_p(void *data
);
419 static int nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
);
421 struct nickserv_config nickserv_conf
;
423 /* We have 2^32 unique account IDs to use. */
424 unsigned long int highest_id
= 0;
427 canonicalize_hostmask(char *mask
)
429 char *out
= mask
, *temp
;
430 if ((temp
= strchr(mask
, '!'))) {
432 while (*temp
) *out
++ = *temp
++;
438 static struct handle_note
*
439 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
441 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
443 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
445 memcpy(note
->note
, text
, strlen(text
));
449 static struct handle_info
*
450 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
452 struct handle_info
*hi
;
454 hi
= calloc(1, sizeof(*hi
));
455 hi
->userlist_style
= nickserv_conf
.default_style
? nickserv_conf
.default_style
: HI_DEFAULT_STYLE
;
456 hi
->announcements
= '?';
457 hi
->handle
= strdup(handle
);
458 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
460 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
466 register_nick(const char *nick
, struct handle_info
*owner
)
468 struct nick_info
*ni
;
469 ni
= malloc(sizeof(struct nick_info
));
470 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
472 ni
->next
= owner
->nicks
;
474 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
478 delete_nick(struct nick_info
*ni
)
480 struct nick_info
*last
, *next
;
481 struct userNode
*user
;
482 /* Check to see if we should mark a user as unregistered. */
483 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
484 user
->modes
&= ~FLAGS_REGNICK
;
487 /* Remove ni from the nick_info linked list. */
488 if (ni
== ni
->owner
->nicks
) {
489 ni
->owner
->nicks
= ni
->next
;
491 last
= ni
->owner
->nicks
;
497 last
->next
= next
->next
;
499 dict_remove(nickserv_nick_dict
, ni
->nick
);
502 static unreg_func_t
*unreg_func_list
;
503 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
506 reg_unreg_func(unreg_func_t func
)
508 if (unreg_func_used
== unreg_func_size
) {
509 if (unreg_func_size
) {
510 unreg_func_size
<<= 1;
511 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
514 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
517 unreg_func_list
[unreg_func_used
++] = func
;
521 nickserv_free_cookie(void *data
)
523 struct handle_cookie
*cookie
= data
;
524 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
525 if (cookie
->data
) free(cookie
->data
);
530 free_handle_info(void *vhi
)
532 struct handle_info
*hi
= vhi
;
534 free_string_list(hi
->masks
);
535 free_string_list(hi
->ignores
);
539 delete_nick(hi
->nicks
);
545 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
546 nickserv_free_cookie(hi
->cookie
);
548 if (hi
->email_addr
) {
549 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
550 handle_info_list_remove(hil
, hi
);
552 dict_remove(nickserv_email_dict
, hi
->email_addr
);
557 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
560 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
563 struct userNode
*uNode
;
566 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
568 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
569 if( (rc
= ldap_delete_account(hi
->handle
)) != LDAP_SUCCESS
) {
571 send_message(notify
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
573 if(rc
!= LDAP_NO_SUCH_OBJECT
)
574 return false; /* if theres noone there to delete, its kinda ok, right ?:) */
579 for (n
=0; n
<unreg_func_used
; n
++)
580 unreg_func_list
[n
](notify
, hi
);
582 if (nickserv_conf
.sync_log
) {
583 uNode
= GetUserH(hi
->users
->nick
);
587 set_user_handle_info(hi
->users
, NULL
, 0);
590 if (nickserv_conf
.disable_nicks
)
591 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
593 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
596 if (nickserv_conf
.sync_log
)
597 SyncLog("UNREGISTER %s", hi
->handle
);
599 dict_remove(nickserv_handle_dict
, hi
->handle
);
604 get_handle_info(const char *handle
)
606 return dict_find(nickserv_handle_dict
, handle
, 0);
610 get_nick_info(const char *nick
)
612 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
616 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
621 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
622 mn
= channel
->members
.list
[nn
];
623 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
630 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
631 if (!user
->handle_info
) {
633 send_message(user
, bot
, "MSG_AUTHENTICATE");
637 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
639 send_message(user
, bot
, "NSMSG_NO_ACCESS");
643 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
645 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
649 if (user
->handle_info
->opserv_level
< min_level
) {
651 send_message(user
, bot
, "NSMSG_NO_ACCESS");
659 is_valid_handle(const char *handle
)
661 struct userNode
*user
;
662 /* cant register a juped nick/service nick as handle, to prevent confusion */
663 user
= GetUserH(handle
);
664 if (user
&& IsLocal(user
))
666 /* check against maximum length */
667 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
669 /* for consistency, only allow account names that could be nicks */
670 if (!is_valid_nick(handle
))
672 /* disallow account names that look like bad words */
673 if (opserv_bad_channel(handle
))
675 /* test either regex or containing all valid chars */
676 if (nickserv_conf
.valid_handle_regex_set
) {
677 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
680 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
681 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
685 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
690 is_registerable_nick(const char *nick
)
692 struct userNode
*user
;
693 /* cant register a juped nick/service nick as nick, to prevent confusion */
694 user
= GetUserH(nick
);
695 if (user
&& IsLocal(user
))
697 /* for consistency, only allow nicks names that could be nicks */
698 if (!is_valid_nick(nick
))
700 /* disallow nicks that look like bad words */
701 if (opserv_bad_channel(nick
))
704 if (strlen(nick
) > NICKLEN
)
706 /* test either regex or as valid handle */
707 if (nickserv_conf
.valid_nick_regex_set
) {
708 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
711 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
712 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
718 /* this has been replaced with one in tools.c
721 is_valid_email_addr(const char *email)
723 return strchr(email, '@') != NULL;
729 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
731 if (hi
->email_addr
) {
732 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
733 return hi
->email_addr
;
743 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
745 struct handle_info
*hi
;
746 struct userNode
*target
;
750 if (!(hi
= get_handle_info(++name
))) {
751 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
756 if (!(target
= GetUserH(name
))) {
757 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
760 if (IsLocal(target
)) {
761 if (IsService(target
))
762 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
764 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
767 if (!(hi
= target
->handle_info
)) {
768 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
776 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
777 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
779 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
780 if ((user
->handle_info
->opserv_level
== 1000)
781 || (user
->handle_info
== hi
)
782 || ((user
->handle_info
->opserv_level
== 0)
783 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
784 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
788 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
793 get_victim_oper(struct userNode
*user
, const char *target
)
795 struct handle_info
*hi
;
796 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
798 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
799 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
802 return oper_outranks(user
, hi
) ? hi
: NULL
;
806 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
810 /* If no hostmasks on the account, allow it. */
811 if (!hi
->masks
->used
)
813 /* If any hostmask matches, allow it. */
814 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
815 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0, 0))
817 /* If they are allowauthed to this account, allow it (removing the aa). */
818 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
819 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
822 /* The user is not allowed to use this account. */
827 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
830 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
834 if (len
< nickserv_conf
.password_min_length
) {
836 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
839 if (!irccasecmp(pass
, handle
)) {
841 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
844 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
847 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
850 for (i
=0; i
<len
; i
++) {
851 if (isdigit(pass
[i
]))
853 if (isupper(pass
[i
]))
855 if (islower(pass
[i
]))
858 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
859 || (cnt_upper
< nickserv_conf
.password_min_upper
)
860 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
862 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
868 static auth_func_t
*auth_func_list
;
869 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
872 reg_auth_func(auth_func_t func
)
874 if (auth_func_used
== auth_func_size
) {
875 if (auth_func_size
) {
876 auth_func_size
<<= 1;
877 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
880 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
883 auth_func_list
[auth_func_used
++] = func
;
886 static handle_rename_func_t
*rf_list
;
887 static unsigned int rf_list_size
, rf_list_used
;
890 reg_handle_rename_func(handle_rename_func_t func
)
892 if (rf_list_used
== rf_list_size
) {
895 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
898 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
901 rf_list
[rf_list_used
++] = func
;
905 generate_fakehost(struct handle_info
*handle
)
907 struct userNode
*target
;
908 extern const char *hidden_host_suffix
;
909 static char buffer
[HOSTLEN
+1];
913 if (!handle
->fakehost
) {
914 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
919 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
920 else if (style
== 2) {
921 /* Due to the way fakehost is coded theres no way i can
922 get the exact user, so for now ill just take the first
924 for (target
= handle
->users
; target
; target
= target
->next_authed
)
927 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
930 } else if (handle
->fakehost
[0] == '.') {
931 /* A leading dot indicates the stored value is actually a title. */
932 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
935 return handle
->fakehost
;
939 apply_fakehost(struct handle_info
*handle
)
941 struct userNode
*target
;
946 fake
= generate_fakehost(handle
);
947 for (target
= handle
->users
; target
; target
= target
->next_authed
)
948 assign_fakehost(target
, fake
, 1);
951 void send_func_list(struct userNode
*user
)
954 struct handle_info
*old_info
;
956 old_info
= user
->handle_info
;
958 for (n
=0; n
<auth_func_used
; n
++)
959 auth_func_list
[n
](user
, old_info
);
963 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
966 struct handle_info
*old_info
;
968 /* This can happen if somebody uses COOKIE while authed, or if
969 * they re-auth to their current handle (which is silly, but users
971 if (user
->handle_info
== hi
)
974 if (user
->handle_info
) {
975 struct userNode
*other
;
978 userList_remove(&curr_helpers
, user
);
980 /* remove from next_authed linked list */
981 if (user
->handle_info
->users
== user
) {
982 user
->handle_info
->users
= user
->next_authed
;
983 } else if (user
->handle_info
->users
!= NULL
) {
984 for (other
= user
->handle_info
->users
;
985 other
->next_authed
!= user
;
986 other
= other
->next_authed
) ;
987 other
->next_authed
= user
->next_authed
;
989 /* No users authed to the account - can happen if they get
990 * killed for authing. */
992 /* if nobody left on old handle, and they're not an oper, remove !god */
993 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
994 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
995 /* record them as being last seen at this time */
996 user
->handle_info
->lastseen
= now
;
997 /* and record their hostmask */
998 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
1000 old_info
= user
->handle_info
;
1001 user
->handle_info
= hi
;
1002 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1003 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1005 /* Call auth handlers */
1006 if (!GetUserH(user
->nick
))
1010 struct nick_info
*ni
;
1012 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1013 if (nickserv_conf
.warn_clone_auth
) {
1014 struct userNode
*other
;
1015 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1016 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1019 /* Add this auth to users list of current auths */
1020 user
->next_authed
= hi
->users
;
1023 /* Add to helpers list */
1024 if (IsHelper(user
) && !userList_contains(&curr_helpers
, user
))
1025 userList_append(&curr_helpers
, user
);
1027 /* Set the fakehost */
1028 if (hi
->fakehost
|| old_info
)
1032 #ifdef WITH_PROTOCOL_P10
1033 /* Stamp users with their account name. */
1034 char *id
= hi
->handle
;
1036 const char *id
= "???";
1038 /* Mark all the nicks registered to this
1039 * account as registered nicks
1040 * - Why not just this one? -rubin */
1041 if (!nickserv_conf
.disable_nicks
) {
1042 struct nick_info
*ni2
;
1043 for (ni2
= hi
->nicks
; ni2
; ni2
= ni2
->next
) {
1044 if (!irccasecmp(user
->nick
, ni2
->nick
)) {
1045 user
->modes
|= FLAGS_REGNICK
;
1050 /* send the account to the ircd */
1051 StampUser(user
, id
, hi
->registered
);
1054 /* Stop trying to kick this user off their nick */
1055 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1056 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1058 /* We cannot clear the user's account ID, unfortunately. */
1059 user
->next_authed
= NULL
;
1062 /* Call auth handlers */
1063 if (GetUserH(user
->nick
)) {
1064 for (n
=0; n
<auth_func_used
; n
++) {
1065 auth_func_list
[n
](user
, old_info
);
1072 static struct handle_info
*
1073 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1075 struct handle_info
*hi
;
1076 struct nick_info
*ni
;
1077 char crypted
[MD5_CRYPT_LENGTH
];
1079 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1081 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1085 if(strlen(handle
) > 30)
1088 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 30);
1092 if (!is_secure_password(handle
, passwd
, user
))
1095 cryptpass(passwd
, crypted
);
1097 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1099 rc
= ldap_do_add(handle
, crypted
, NULL
);
1100 if(LDAP_SUCCESS
!= rc
&& LDAP_ALREADY_EXISTS
!= rc
) {
1102 send_message(user
, nickserv
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1107 hi
= register_handle(handle
, crypted
, 0);
1108 hi
->masks
= alloc_string_list(1);
1109 hi
->ignores
= alloc_string_list(1);
1111 hi
->language
= lang_C
;
1112 hi
->registered
= now
;
1114 hi
->flags
= HI_DEFAULT_FLAGS
;
1115 if (settee
&& !no_auth
)
1116 set_user_handle_info(settee
, hi
, 1);
1118 if (user
!= settee
) {
1120 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1122 else if (nickserv_conf
.disable_nicks
) {
1124 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1127 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
))) {
1129 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1134 if (is_registerable_nick(user
->nick
)) {
1135 register_nick(user
->nick
, hi
);
1136 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1140 if (settee
&& (user
!= settee
)) {
1142 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1149 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1151 cookie
->hi
->cookie
= cookie
;
1152 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1155 /* Contributed by the great sneep of afternet ;) */
1156 /* Since this gets used in a URL, we want to avoid stuff that confuses
1157 * email clients such as ] and ?. a-z, 0-9 only.
1159 void genpass(char *str
, int len
)
1164 for(i
= 0; i
< len
; i
++)
1168 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1169 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1177 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1179 struct handle_cookie
*cookie
;
1180 char subject
[128], body
[4096], *misc
;
1181 const char *netname
, *fmt
;
1185 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1189 cookie
= calloc(1, sizeof(*cookie
));
1191 cookie
->type
= type
;
1192 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1194 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1195 /* Adding dedicated password gen function for more control -Rubin */
1196 genpass(cookie
->cookie
, 10);
1198 *inttobase64(cookie->cookie, rand(), 5);
1199 *inttobase64(cookie->cookie+5, rand(), 5);
1202 netname
= nickserv_conf
.network_name
;
1205 switch (cookie
->type
) {
1207 hi
->passwd
[0] = 0; /* invalidate password */
1208 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1209 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1210 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1213 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1215 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1217 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1220 case PASSWORD_CHANGE
:
1221 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1222 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1223 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1225 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1227 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1228 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1232 misc
= hi
->email_addr
;
1233 hi
->email_addr
= cookie
->data
;
1234 #ifdef stupid_verify_old_email
1236 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1237 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1238 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1239 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1240 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1241 mail_send(nickserv
, hi
, subject
, body
, 1);
1242 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1243 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1247 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1248 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1249 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1250 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1251 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1252 mail_send(nickserv
, hi
, subject
, body
, 1);
1254 #ifdef stupid_verify_old_email
1257 hi
->email_addr
= misc
;
1260 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1261 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1262 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1263 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1264 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1267 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1271 mail_send(nickserv
, hi
, subject
, body
, first_time
);
1272 nickserv_bake_cookie(cookie
);
1276 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1278 cookie
->hi
->cookie
= NULL
;
1279 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1280 nickserv_free_cookie(cookie
);
1284 nickserv_free_email_addr(void *data
)
1286 handle_info_list_clean(data
);
1291 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1293 struct handle_info_list
*hil
;
1294 /* Remove from old handle_info_list ... */
1295 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1296 handle_info_list_remove(hil
, hi
);
1297 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1298 hi
->email_addr
= NULL
;
1300 /* Add to the new list.. */
1301 if (new_email_addr
) {
1302 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1303 hil
= calloc(1, sizeof(*hil
));
1304 hil
->tag
= strdup(new_email_addr
);
1305 handle_info_list_init(hil
);
1306 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1308 handle_info_list_append(hil
, hi
);
1309 hi
->email_addr
= hil
->tag
;
1313 static NICKSERV_FUNC(cmd_register
)
1316 struct handle_info
*hi
;
1317 const char *email_addr
, *password
;
1318 char syncpass
[MD5_CRYPT_LENGTH
];
1319 int no_auth
, weblink
;
1321 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1322 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1326 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1327 /* Require the first handle registered to belong to someone +o. */
1328 reply("NSMSG_REQUIRE_OPER");
1332 if (user
->handle_info
) {
1333 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1337 if (IsRegistering(user
)) {
1338 reply("NSMSG_ALREADY_REGISTERING");
1342 if (IsStamped(user
)) {
1343 /* Unauthenticated users might still have been stamped
1344 previously and could therefore have a hidden host;
1345 do not allow them to register a new account. */
1346 reply("NSMSG_STAMPED_REGISTER");
1350 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1352 if(nickserv_conf
.force_handles_lowercase
)
1353 irc_strtolower(argv
[1]);
1354 if (!is_valid_handle(argv
[1])) {
1355 reply("NSMSG_BAD_HANDLE", argv
[1]);
1360 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1361 struct handle_info_list
*hil
;
1364 /* Remember email address. */
1365 email_addr
= argv
[3];
1367 /* Check that the email address looks valid.. */
1368 if (!valid_email(email_addr
)) {
1369 reply("NSMSG_BAD_EMAIL_ADDR");
1373 /* .. and that we are allowed to send to it. */
1374 if ((str
= mail_prohibited_address(email_addr
))) {
1375 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1379 /* If we do email verify, make sure we don't spam the address. */
1380 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1382 for (nn
=0; nn
<hil
->used
; nn
++) {
1383 if (hil
->list
[nn
]->cookie
) {
1384 reply("NSMSG_EMAIL_UNACTIVATED");
1388 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1389 reply("NSMSG_EMAIL_OVERUSED");
1402 /* Webregister hack - send URL instead of IRC cookie
1405 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1409 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1411 /* Add any masks they should get. */
1412 if (nickserv_conf
.default_hostmask
) {
1413 string_list_append(hi
->masks
, strdup("*@*"));
1415 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1416 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1417 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1420 /* If they're the first to register, give them level 1000. */
1421 if (dict_size(nickserv_handle_dict
) == 1) {
1422 hi
->opserv_level
= 1000;
1423 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1426 /* Set their email address. */
1429 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1431 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email_addr
)) != LDAP_SUCCESS
) {
1432 /* Falied to update email in ldap, but still
1433 * updated it here.. what should we do? */
1434 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1436 nickserv_set_email_addr(hi
, email_addr
);
1440 nickserv_set_email_addr(hi
, email_addr
);
1443 nickserv_set_email_addr(hi
, email_addr
);
1447 /* If they need to do email verification, tell them. */
1449 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1451 /* Set registering flag.. */
1452 user
->modes
|= FLAGS_REGISTERING
;
1454 if (nickserv_conf
.sync_log
) {
1455 cryptpass(password
, syncpass
);
1457 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1458 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1461 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1464 /* this wont work if email is required .. */
1465 process_adduser_pending(user
);
1470 static NICKSERV_FUNC(cmd_oregister
)
1472 struct userNode
*settee
= NULL
;
1473 struct handle_info
*hi
;
1474 char* account
= NULL
;
1480 NICKSERV_MIN_PARMS(2);
1484 if(nickserv_conf
.force_handles_lowercase
)
1485 irc_strtolower(account
);
1486 if (nickserv_conf
.email_required
) {
1487 NICKSERV_MIN_PARMS(3);
1489 if (argc
>= 4) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1493 } else if (strchr(argv
[4], '@'))
1503 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1507 } else if (strchr(argv
[3], '@'))
1516 /* If they passed a nick, look for that user.. */
1517 if (nick
&& !(settee
= GetUserH(nick
))) {
1518 reply("MSG_NICK_UNKNOWN", argv
[4]);
1521 /* If the setee is already authed, we cant add a 2nd account for them.. */
1522 if (settee
&& settee
->handle_info
) {
1523 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1526 /* If there is no default mask in the conf, and they didn't pass a mask,
1527 * but we did find a user by nick, generate the mask */
1529 if (nickserv_conf
.default_hostmask
)
1532 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1534 reply("NSMSG_REGISTER_BAD_NICKMASK");
1539 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1540 return 0; /* error reply handled by above */
1544 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1546 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email
)) != LDAP_SUCCESS
) {
1547 /* Falied to update email in ldap, but still
1548 * updated it here.. what should we do? */
1549 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1551 nickserv_set_email_addr(hi
, email
);
1555 nickserv_set_email_addr(hi
, email
);
1558 nickserv_set_email_addr(hi
, email
);
1562 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1563 if (mask_canonicalized
)
1564 string_list_append(hi
->masks
, mask_canonicalized
);
1567 if (nickserv_conf
.sync_log
)
1568 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1573 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1576 struct userNode
*target
;
1577 char *new_mask
= strdup(pretty_mask(mask
));
1578 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1579 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1580 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1585 string_list_append(hi
->ignores
, new_mask
);
1586 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1588 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1589 irc_silence(target
, new_mask
, 1);
1594 static NICKSERV_FUNC(cmd_addignore
)
1596 NICKSERV_MIN_PARMS(2);
1598 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1601 static NICKSERV_FUNC(cmd_oaddignore
)
1603 struct handle_info
*hi
;
1605 NICKSERV_MIN_PARMS(3);
1606 if (!(hi
= get_victim_oper(user
, argv
[1])))
1609 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1613 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1616 struct userNode
*target
;
1617 char *pmask
= strdup(pretty_mask(del_mask
));
1618 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1619 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1620 char *old_mask
= hi
->ignores
->list
[i
];
1621 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1622 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1623 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1624 irc_silence(target
, old_mask
, 0);
1631 reply("NSMSG_DELMASK_NOT_FOUND");
1635 static NICKSERV_FUNC(cmd_delignore
)
1637 NICKSERV_MIN_PARMS(2);
1638 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1641 static NICKSERV_FUNC(cmd_odelignore
)
1643 struct handle_info
*hi
;
1644 NICKSERV_MIN_PARMS(3);
1645 if (!(hi
= get_victim_oper(user
, argv
[1])))
1647 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1650 static NICKSERV_FUNC(cmd_handleinfo
)
1653 unsigned int i
, pos
=0, herelen
;
1654 struct userNode
*target
, *next_un
;
1655 struct handle_info
*hi
;
1656 const char *nsmsg_none
;
1659 if (!(hi
= user
->handle_info
)) {
1660 reply("NSMSG_MUST_AUTH");
1663 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1667 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1668 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1670 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1673 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1674 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1676 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1679 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1680 if (HANDLE_FLAGGED(hi
, FROZEN
))
1681 reply("NSMSG_HANDLEINFO_VACATION");
1683 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1684 struct do_not_register
*dnr
;
1685 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1686 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1687 if ((user
->handle_info
->opserv_level
< 900) && !oper_outranks(user
, hi
))
1689 } else if (hi
!= user
->handle_info
) {
1690 reply("NSMSG_HANDLEINFO_END");
1695 reply("NSMSG_HANDLEINFO_KARMA", hi
->karma
);
1697 if (nickserv_conf
.email_enabled
)
1698 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1702 switch (hi
->cookie
->type
) {
1703 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1704 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1705 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1706 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1707 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1713 unsigned long flen
= 1;
1714 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1716 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1717 if (hi
->flags
& 1 << i
)
1718 flags
[flen
++] = handle_flags
[i
];
1720 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1722 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1725 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1726 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1727 || (hi
->opserv_level
> 0)) {
1728 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1731 if (IsHelping(user
) || IsOper(user
))
1736 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1737 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1742 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1744 if (hi
->last_quit_host
[0])
1745 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1747 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1749 if (nickserv_conf
.disable_nicks
) {
1750 /* nicks disabled; don't show anything about registered nicks */
1751 } else if (hi
->nicks
) {
1752 struct nick_info
*ni
, *next_ni
;
1753 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1754 herelen
= strlen(ni
->nick
);
1755 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1757 goto print_nicks_buff
;
1761 memcpy(buff
+pos
, ni
->nick
, herelen
);
1762 pos
+= herelen
; buff
[pos
++] = ' ';
1766 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1771 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1774 if (hi
->masks
->used
) {
1775 for (i
=0; i
< hi
->masks
->used
; i
++) {
1776 herelen
= strlen(hi
->masks
->list
[i
]);
1777 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1779 goto print_mask_buff
;
1781 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1782 pos
+= herelen
; buff
[pos
++] = ' ';
1783 if (i
+1 == hi
->masks
->used
) {
1786 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1791 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1794 if (hi
->ignores
->used
) {
1795 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1796 herelen
= strlen(hi
->ignores
->list
[i
]);
1797 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1799 goto print_ignore_buff
;
1801 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1802 pos
+= herelen
; buff
[pos
++] = ' ';
1803 if (i
+1 == hi
->ignores
->used
) {
1806 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1811 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1815 struct userData
*chan
, *next
;
1818 for (chan
= hi
->channels
; chan
; chan
= next
) {
1819 next
= chan
->u_next
;
1820 name
= chan
->channel
->channel
->name
;
1821 herelen
= strlen(name
);
1822 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1824 goto print_chans_buff
;
1826 if (IsUserSuspended(chan
))
1828 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(chan
->access
), name
);
1832 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1837 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1840 for (target
= hi
->users
; target
; target
= next_un
) {
1841 herelen
= strlen(target
->nick
);
1842 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1844 goto print_cnick_buff
;
1846 next_un
= target
->next_authed
;
1848 memcpy(buff
+pos
, target
->nick
, herelen
);
1849 pos
+= herelen
; buff
[pos
++] = ' ';
1853 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1858 reply("NSMSG_HANDLEINFO_END");
1859 return 1 | ((hi
!= user
->handle_info
) ? CMD_LOG_STAFF
: 0);
1862 static NICKSERV_FUNC(cmd_userinfo
)
1864 struct userNode
*target
;
1866 NICKSERV_MIN_PARMS(2);
1867 if (!(target
= GetUserH(argv
[1]))) {
1868 reply("MSG_NICK_UNKNOWN", argv
[1]);
1871 if (target
->handle_info
)
1872 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1874 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1878 static NICKSERV_FUNC(cmd_nickinfo
)
1880 struct nick_info
*ni
;
1882 NICKSERV_MIN_PARMS(2);
1883 if (!(ni
= get_nick_info(argv
[1]))) {
1884 reply("MSG_NICK_UNKNOWN", argv
[1]);
1887 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1891 static NICKSERV_FUNC(cmd_rename_handle
)
1893 struct handle_info
*hi
;
1894 struct userNode
*uNode
;
1898 NICKSERV_MIN_PARMS(3);
1899 if(nickserv_conf
.force_handles_lowercase
)
1900 irc_strtolower(argv
[2]);
1901 if (!(hi
= get_victim_oper(user
, argv
[1])))
1903 if (!is_valid_handle(argv
[2])) {
1904 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1907 if (get_handle_info(argv
[2])) {
1908 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1911 if(strlen(argv
[2]) > 30)
1913 reply("NMSG_HANDLE_TOLONG", argv
[2], 30);
1917 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1919 if( (rc
= ldap_rename_account(hi
->handle
, argv
[2])) != LDAP_SUCCESS
) {
1920 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1926 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1927 hi
->handle
= strdup(argv
[2]);
1928 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1929 for (nn
=0; nn
<rf_list_used
; nn
++)
1930 rf_list
[nn
](hi
, old_handle
);
1932 if (nickserv_conf
.sync_log
) {
1933 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1934 irc_rename(uNode
, hi
->handle
);
1936 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1939 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1940 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1941 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1947 static failpw_func_t
*failpw_func_list
;
1948 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1951 reg_failpw_func(failpw_func_t func
)
1953 if (failpw_func_used
== failpw_func_size
) {
1954 if (failpw_func_size
) {
1955 failpw_func_size
<<= 1;
1956 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1958 failpw_func_size
= 8;
1959 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1962 failpw_func_list
[failpw_func_used
++] = func
;
1966 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1968 * called by nefariouses enhanced AC login-on-connect code
1971 struct handle_info
*loc_auth(char *handle
, char *password
, char *userhost
)
1973 int pw_arg
, used
, maxlogins
;
1976 struct handle_info
*hi
;
1977 struct userNode
*other
;
1979 int ldap_result
= LDAP_SUCCESS
;
1983 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1987 if(nickserv_conf
.ldap_enable
) {
1988 ldap_result
= ldap_check_auth(handle
, password
);
1989 if(ldap_result
!= LDAP_SUCCESS
) {
1998 if (!checkpass(password
, hi
->passwd
)) {
2003 /* ldap libs are present but we are not using them... */
2004 if( !nickserv_conf
.ldap_enable
) {
2008 if (!checkpass(password
, hi
->passwd
)) {
2012 else if( (!hi
) && ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2013 /* user not found, but authed to ldap successfully..
2014 * create the account.
2019 /* Add a *@* mask */
2020 /* TODO if userhost is not null, build mask based on that. */
2021 if(nickserv_conf
.default_hostmask
)
2024 return NULL
; /* They dont have a *@* mask so they can't loc */
2026 if(!(hi
= nickserv_register(NULL
, NULL
, handle
, password
, 0))) {
2027 return 0; /* couldn't add the user for some reason */
2030 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2032 if(nickserv_conf
.email_required
) {
2037 nickserv_set_email_addr(hi
, email
);
2041 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2042 string_list_append(hi
->masks
, mask_canonicalized
);
2044 if(nickserv_conf
.sync_log
)
2045 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, "@", handle
);
2049 /* Still no account, so just fail out */
2054 /* We don't know the users hostname, or anything because they
2055 * havn't registered yet. So we can only allow LOC if your
2056 * account has *@* as a hostmask.
2058 * UPDATE: New nefarious LOC supports u@h
2068 buf
= strdup(userhost
);
2069 ident
= mysep(&buf
, "@");
2070 realhost
= mysep(&buf
, ":");
2071 ip
= mysep(&buf
, ":");
2072 if(!ip
|| !realhost
|| !ident
) {
2074 return NULL
; /* Invalid AC request, just quit */
2076 uh
= malloc(strlen(userhost
));
2077 ui
= malloc(strlen(userhost
));
2078 sprintf(uh
, "%s@%s", ident
, realhost
);
2079 sprintf(ui
, "%s@%s", ident
, ip
);
2080 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2082 if(match_ircglob(uh
, hi
->masks
->list
[ii
])
2083 || match_ircglob(ui
, hi
->masks
->list
[ii
]))
2095 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2097 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
2107 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2111 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2112 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2113 if (++used
>= maxlogins
) {
2117 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2121 static NICKSERV_FUNC(cmd_auth
)
2123 int pw_arg
, used
, maxlogins
;
2124 struct handle_info
*hi
;
2126 struct userNode
*other
;
2128 int ldap_result
= LDAP_OTHER
;
2132 if (user
->handle_info
) {
2133 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2136 if (IsStamped(user
)) {
2137 /* Unauthenticated users might still have been stamped
2138 previously and could therefore have a hidden host;
2139 do not allow them to authenticate. */
2140 reply("NSMSG_STAMPED_AUTH");
2145 if(strchr(argv
[1], '<') || strchr(argv
[1], '>')) {
2146 reply("NSMSG_NO_ANGLEBRACKETS");
2149 if (!is_valid_handle(argv
[1])) {
2150 reply("NSMSG_BAD_HANDLE", argv
[1]);
2154 if(nickserv_conf
.ldap_enable
) {
2155 ldap_result
= ldap_check_auth(argv
[1], argv
[2]);
2156 /* Get the users email address and update it */
2157 if(ldap_result
== LDAP_SUCCESS
) {
2159 if((rc
= ldap_get_user_info(argv
[1], &email
) != LDAP_SUCCESS
))
2161 if(nickserv_conf
.email_required
) {
2162 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc
));
2167 else if(ldap_result
!= LDAP_INVALID_CREDENTIALS
) {
2168 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2174 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
2176 } else if (argc
== 2 && !nickserv_conf
.ldap_enable
) {
2177 if (nickserv_conf
.disable_nicks
) {
2178 if (!(hi
= get_handle_info(user
->nick
))) {
2179 reply("NSMSG_HANDLE_NOT_FOUND");
2183 /* try to look up their handle from their nick */
2184 /* TODO: handle ldap auth on nickserv style networks, too */
2185 struct nick_info
*ni
;
2186 ni
= get_nick_info(user
->nick
);
2188 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
2195 reply("MSG_MISSING_PARAMS", argv
[0]);
2196 svccmd_send_help_brief(user
, nickserv
, cmd
);
2201 if(nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2202 /* user not found, but authed to ldap successfully..
2203 * create the account.
2206 if(!(hi
= nickserv_register(user
, NULL
, argv
[1], argv
[2], 0))) {
2207 reply("NSMSG_UNABLE_TO_ADD");
2208 return 0; /* couldn't add the user for some reason */
2210 /* Add a *@* mask */
2211 if(nickserv_conf
.default_hostmask
)
2214 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2217 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2218 string_list_append(hi
->masks
, mask_canonicalized
);
2221 nickserv_set_email_addr(hi
, email
);
2224 if(nickserv_conf
.sync_log
)
2225 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
);
2229 reply("NSMSG_HANDLE_NOT_FOUND");
2235 /* Responses from here on look up the language used by the handle they asked about. */
2236 passwd
= argv
[pw_arg
];
2237 if (!valid_user_for(user
, hi
)) {
2238 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
2239 send_message_type(4, user
, cmd
->parent
->bot
,
2240 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
2243 send_message_type(4, user
, cmd
->parent
->bot
,
2244 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
2246 argv
[pw_arg
] = "BADMASK";
2250 if( ( nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_INVALID_CREDENTIALS
) ||
2251 ( (!nickserv_conf
.ldap_enable
) && (!checkpass(passwd
, hi
->passwd
)) ) ) {
2253 if (!checkpass(passwd
, hi
->passwd
)) {
2256 send_message_type(4, user
, cmd
->parent
->bot
,
2257 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
2258 argv
[pw_arg
] = "BADPASS";
2259 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
2260 if (nickserv_conf
.autogag_enabled
) {
2261 if (!user
->auth_policer
.params
) {
2262 user
->auth_policer
.last_req
= now
;
2263 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
2265 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
2267 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
2268 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
2269 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2271 argv
[pw_arg
] = "GAGGED";
2276 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2277 send_message_type(4, user
, cmd
->parent
->bot
,
2278 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2279 argv
[pw_arg
] = "SUSPENDED";
2282 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2283 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2284 if (++used
>= maxlogins
) {
2285 send_message_type(4, user
, cmd
->parent
->bot
,
2286 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2288 argv
[pw_arg
] = "MAXLOGINS";
2293 set_user_handle_info(user
, hi
, 1);
2294 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2295 reply("NSMSG_PLEASE_SET_EMAIL");
2296 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2297 reply("NSMSG_WEAK_PASSWORD");
2298 if (hi
->passwd
[0] != '$')
2299 cryptpass(passwd
, hi
->passwd
);
2301 /* If a channel was waiting for this user to auth,
2302 * finish adding them */
2303 process_adduser_pending(user
);
2305 reply("NSMSG_AUTH_SUCCESS");
2308 /* Set +x if autohide is on */
2309 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2310 irc_umode(user
, "+x");
2312 if(!IsOper(user
)) /* If they arnt already opered.. */
2314 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2315 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2317 irc_umode(user
,nickserv_conf
.auto_admin
);
2318 reply("NSMSG_AUTO_OPER_ADMIN");
2320 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2322 irc_umode(user
,nickserv_conf
.auto_oper
);
2323 reply("NSMSG_AUTO_OPER");
2327 /* Wipe out the pass for the logs */
2329 if (!hi
->masks
->used
) {
2331 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2332 if (irc_in_addr_is_valid(user
->ip
) && irc_pton(&ip
, NULL
, user
->hostname
))
2333 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2336 argv
[pw_arg
] = "****";
2340 static allowauth_func_t
*allowauth_func_list
;
2341 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2344 reg_allowauth_func(allowauth_func_t func
)
2346 if (allowauth_func_used
== allowauth_func_size
) {
2347 if (allowauth_func_size
) {
2348 allowauth_func_size
<<= 1;
2349 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2351 allowauth_func_size
= 8;
2352 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2355 allowauth_func_list
[allowauth_func_used
++] = func
;
2358 static NICKSERV_FUNC(cmd_allowauth
)
2360 struct userNode
*target
;
2361 struct handle_info
*hi
;
2364 NICKSERV_MIN_PARMS(2);
2365 if (!(target
= GetUserH(argv
[1]))) {
2366 reply("MSG_NICK_UNKNOWN", argv
[1]);
2369 if (target
->handle_info
) {
2370 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2373 if (IsStamped(target
)) {
2374 /* Unauthenticated users might still have been stamped
2375 previously and could therefore have a hidden host;
2376 do not allow them to authenticate to an account. */
2377 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2382 else if (!(hi
= get_handle_info(argv
[2]))) {
2383 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2387 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2388 reply("MSG_USER_OUTRANKED", hi
->handle
);
2391 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2392 || (hi
->opserv_level
> 0))
2393 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2394 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2397 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2398 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2399 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2400 if (nickserv_conf
.email_enabled
)
2401 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2403 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2404 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2406 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2408 for (n
=0; n
<allowauth_func_used
; n
++)
2409 allowauth_func_list
[n
](user
, target
, hi
);
2413 static NICKSERV_FUNC(cmd_authcookie
)
2415 struct handle_info
*hi
;
2417 NICKSERV_MIN_PARMS(2);
2418 if (user
->handle_info
) {
2419 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2422 if (IsStamped(user
)) {
2423 /* Unauthenticated users might still have been stamped
2424 previously and could therefore have a hidden host;
2425 do not allow them to authenticate to an account. */
2426 reply("NSMSG_STAMPED_AUTHCOOKIE");
2429 if (!(hi
= get_handle_info(argv
[1]))) {
2430 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2433 if (!hi
->email_addr
) {
2434 reply("MSG_SET_EMAIL_ADDR");
2437 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2441 static NICKSERV_FUNC(cmd_delcookie
)
2443 struct handle_info
*hi
;
2445 hi
= user
->handle_info
;
2447 reply("NSMSG_NO_COOKIE");
2450 switch (hi
->cookie
->type
) {
2453 reply("NSMSG_MUST_TIME_OUT");
2456 nickserv_eat_cookie(hi
->cookie
);
2457 reply("NSMSG_ATE_COOKIE");
2463 static NICKSERV_FUNC(cmd_odelcookie
)
2465 struct handle_info
*hi
;
2467 NICKSERV_MIN_PARMS(2);
2469 if (!(hi
= get_victim_oper(user
, argv
[1])))
2473 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2477 switch (hi
->cookie
->type
) {
2479 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2480 if (nickserv_conf
.sync_log
)
2481 SyncLog("ACCOUNTACC %s", hi
->handle
);
2483 case PASSWORD_CHANGE
:
2484 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2485 if (nickserv_conf
.sync_log
)
2486 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2489 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2490 if (nickserv_conf
.sync_log
)
2491 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2494 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2496 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2497 /* Falied to update email in ldap, but still
2498 * updated it here.. what should we do? */
2499 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2501 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2505 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2508 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2510 if (nickserv_conf
.sync_log
)
2511 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2514 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2515 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2519 nickserv_eat_cookie(hi
->cookie
);
2520 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2525 static NICKSERV_FUNC(cmd_resetpass
)
2527 struct handle_info
*hi
;
2528 char crypted
[MD5_CRYPT_LENGTH
];
2531 NICKSERV_MIN_PARMS(3);
2532 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2536 if (user
->handle_info
) {
2537 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2540 if (IsStamped(user
)) {
2541 /* Unauthenticated users might still have been stamped
2542 previously and could therefore have a hidden host;
2543 do not allow them to activate an account. */
2544 reply("NSMSG_STAMPED_RESETPASS");
2547 if (!(hi
= get_handle_info(argv
[1]))) {
2548 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2551 if (!hi
->email_addr
) {
2552 reply("MSG_SET_EMAIL_ADDR");
2555 cryptpass(argv
[2], crypted
);
2557 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2561 static NICKSERV_FUNC(cmd_cookie
)
2563 struct handle_info
*hi
;
2566 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2569 NICKSERV_MIN_PARMS(3);
2570 if (!(hi
= get_handle_info(argv
[1]))) {
2571 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2577 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2578 reply("NSMSG_HANDLE_SUSPENDED");
2583 reply("NSMSG_NO_COOKIE");
2587 /* Check validity of operation before comparing cookie to
2588 * prohibit guessing by authed users. */
2589 if (user
->handle_info
2590 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2591 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2592 reply("NSMSG_CANNOT_COOKIE");
2596 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2597 reply("NSMSG_BAD_COOKIE");
2601 switch (hi
->cookie
->type
) {
2604 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2606 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2607 /* Falied to update email in ldap, but still
2608 * updated it here.. what should we do? */
2609 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2614 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2615 set_user_handle_info(user
, hi
, 1);
2616 reply("NSMSG_HANDLE_ACTIVATED");
2617 if (nickserv_conf
.sync_log
)
2618 SyncLog("ACCOUNTACC %s", hi
->handle
);
2620 case PASSWORD_CHANGE
:
2622 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2624 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2625 /* Falied to update email in ldap, but still
2626 * updated it here.. what should we do? */
2627 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2632 set_user_handle_info(user
, hi
, 1);
2633 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2634 reply("NSMSG_PASSWORD_CHANGED");
2635 if (nickserv_conf
.sync_log
)
2636 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2640 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2642 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2643 /* Falied to update email in ldap, but still
2644 * updated it here.. what should we do? */
2645 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2650 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2652 * This should only happen if an OREGISTER was sent. Require
2653 * email must be enabled! - SiRVulcaN
2655 if (nickserv_conf
.sync_log
)
2656 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2659 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2660 reply("NSMSG_EMAIL_CHANGED");
2661 if (nickserv_conf
.sync_log
)
2662 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2665 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2666 set_user_handle_info(user
, hi
, 1);
2667 nickserv_addmask(user
, hi
, mask
);
2668 reply("NSMSG_AUTH_SUCCESS");
2673 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2674 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2678 nickserv_eat_cookie(hi
->cookie
);
2680 process_adduser_pending(user
);
2685 static NICKSERV_FUNC(cmd_oregnick
) {
2687 struct handle_info
*target
;
2688 struct nick_info
*ni
;
2690 NICKSERV_MIN_PARMS(3);
2691 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2694 if (!is_registerable_nick(nick
)) {
2695 reply("NSMSG_BAD_NICK", nick
);
2698 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2700 reply("NSMSG_NICK_EXISTS", nick
);
2703 register_nick(nick
, target
);
2704 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2708 static NICKSERV_FUNC(cmd_regnick
) {
2710 struct nick_info
*ni
;
2712 if (!is_registerable_nick(user
->nick
)) {
2713 reply("NSMSG_BAD_NICK", user
->nick
);
2716 /* count their nicks, see if it's too many */
2717 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2718 if (n
>= nickserv_conf
.nicks_per_handle
) {
2719 reply("NSMSG_TOO_MANY_NICKS");
2722 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2724 reply("NSMSG_NICK_EXISTS", user
->nick
);
2727 register_nick(user
->nick
, user
->handle_info
);
2728 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2732 static NICKSERV_FUNC(cmd_pass
)
2734 struct handle_info
*hi
;
2735 char *old_pass
, *new_pass
;
2736 char crypted
[MD5_CRYPT_LENGTH
+1];
2741 NICKSERV_MIN_PARMS(3);
2742 hi
= user
->handle_info
;
2746 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2749 if(nickserv_conf
.ldap_enable
) {
2750 ldap_result
= ldap_check_auth(hi
->handle
, old_pass
);
2751 if(ldap_result
!= LDAP_SUCCESS
) {
2752 if(ldap_result
== LDAP_INVALID_CREDENTIALS
)
2753 reply("NSMSG_PASSWORD_INVALID");
2755 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2760 if (!checkpass(old_pass
, hi
->passwd
)) {
2761 argv
[1] = "BADPASS";
2762 reply("NSMSG_PASSWORD_INVALID");
2765 cryptpass(new_pass
, crypted
);
2767 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2769 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
2770 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2775 //cryptpass(new_pass, hi->passwd);
2776 strcpy(hi
->passwd
, crypted
);
2777 if (nickserv_conf
.sync_log
)
2778 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2780 reply("NSMSG_PASS_SUCCESS");
2785 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2788 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2789 for (i
=0; i
<hi
->masks
->used
; i
++) {
2790 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2791 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2796 string_list_append(hi
->masks
, new_mask
);
2797 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2801 static NICKSERV_FUNC(cmd_addmask
)
2804 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2805 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2809 if (!is_gline(argv
[1])) {
2810 reply("NSMSG_MASK_INVALID", argv
[1]);
2813 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2817 static NICKSERV_FUNC(cmd_oaddmask
)
2819 struct handle_info
*hi
;
2821 NICKSERV_MIN_PARMS(3);
2822 if (!(hi
= get_victim_oper(user
, argv
[1])))
2824 return nickserv_addmask(user
, hi
, argv
[2]);
2828 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
, int force
)
2831 for (i
=0; i
<hi
->masks
->used
; i
++) {
2832 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2833 char *old_mask
= hi
->masks
->list
[i
];
2834 if (hi
->masks
->used
== 1 && !force
) {
2835 reply("NSMSG_DELMASK_NOTLAST");
2838 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2839 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2844 reply("NSMSG_DELMASK_NOT_FOUND");
2848 static NICKSERV_FUNC(cmd_delmask
)
2850 NICKSERV_MIN_PARMS(2);
2851 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1], 0);
2854 static NICKSERV_FUNC(cmd_odelmask
)
2856 struct handle_info
*hi
;
2857 NICKSERV_MIN_PARMS(3);
2858 if (!(hi
= get_victim_oper(user
, argv
[1])))
2860 return nickserv_delmask(cmd
, user
, hi
, argv
[2], 1);
2864 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2865 unsigned int nn
, add
= 1, pos
;
2866 unsigned long added
, removed
, flag
;
2868 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2870 case '+': add
= 1; break;
2871 case '-': add
= 0; break;
2873 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2874 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2877 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2878 /* cheesy avoidance of looking up the flag name.. */
2879 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2882 flag
= 1 << (pos
- 1);
2884 added
|= flag
, removed
&= ~flag
;
2886 removed
|= flag
, added
&= ~flag
;
2891 *premoved
= removed
;
2896 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2898 unsigned long before
, after
, added
, removed
;
2899 struct userNode
*uNode
;
2901 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2902 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2904 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2905 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2907 /* Strip helping flag if they're only a support helper and not
2908 * currently in #support. */
2909 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2910 struct channelList
*schannels
;
2912 schannels
= chanserv_support_channels();
2913 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2914 if (find_handle_in_channel(schannels
->list
[ii
], hi
, NULL
))
2916 if (ii
== schannels
->used
)
2917 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2920 if (after
&& !before
) {
2921 /* Add user to current helper list. */
2922 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2923 userList_append(&curr_helpers
, uNode
);
2924 } else if (!after
&& before
) {
2925 /* Remove user from current helper list. */
2926 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2927 userList_remove(&curr_helpers
, uNode
);
2934 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2938 char *set_display
[] = {
2939 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2940 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2941 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2944 reply("NSMSG_SETTING_LIST");
2945 reply("NSMSG_SETTING_LIST_HEADER");
2947 /* Do this so options are presented in a consistent order. */
2948 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2949 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2950 opt(cmd
, user
, hi
, override
, 0, NULL
);
2951 reply("NSMSG_SETTING_LIST_END");
2954 static NICKSERV_FUNC(cmd_set
)
2956 struct handle_info
*hi
;
2959 hi
= user
->handle_info
;
2961 set_list(cmd
, user
, hi
, 0);
2964 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2965 reply("NSMSG_INVALID_OPTION", argv
[1]);
2968 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2971 static NICKSERV_FUNC(cmd_oset
)
2973 struct handle_info
*hi
;
2976 NICKSERV_MIN_PARMS(2);
2978 if (!(hi
= get_victim_oper(user
, argv
[1])))
2982 set_list(cmd
, user
, hi
, 0);
2986 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2987 reply("NSMSG_INVALID_OPTION", argv
[2]);
2991 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
2994 static OPTION_FUNC(opt_info
)
2998 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
3000 hi
->infoline
= NULL
;
3002 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
3006 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
3007 reply("NSMSG_SET_INFO", info
);
3011 static OPTION_FUNC(opt_width
)
3014 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
3016 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
3017 hi
->screen_width
= MIN_LINE_SIZE
;
3018 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3019 hi
->screen_width
= MAX_LINE_SIZE
;
3021 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
3025 static OPTION_FUNC(opt_tablewidth
)
3028 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
3030 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
3031 hi
->table_width
= MIN_LINE_SIZE
;
3032 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3033 hi
->table_width
= MAX_LINE_SIZE
;
3035 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
3039 static OPTION_FUNC(opt_color
)
3042 if (enabled_string(argv
[1]))
3043 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
3044 else if (disabled_string(argv
[1]))
3045 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
3047 reply("MSG_INVALID_BINARY", argv
[1]);
3052 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
3056 static OPTION_FUNC(opt_privmsg
)
3059 if (enabled_string(argv
[1]))
3060 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
3061 else if (disabled_string(argv
[1]))
3062 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
3064 reply("MSG_INVALID_BINARY", argv
[1]);
3069 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
3073 static OPTION_FUNC(opt_autohide
)
3076 if (enabled_string(argv
[1]))
3077 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
3078 else if (disabled_string(argv
[1]))
3079 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
3081 reply("MSG_INVALID_BINARY", argv
[1]);
3086 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
3090 static OPTION_FUNC(opt_style
)
3095 if (!irccasecmp(argv
[1], "Clean"))
3096 hi
->userlist_style
= HI_STYLE_CLEAN
;
3097 else if (!irccasecmp(argv
[1], "Advanced"))
3098 hi
->userlist_style
= HI_STYLE_ADVANCED
;
3099 else if (!irccasecmp(argv
[1], "Classic"))
3100 hi
->userlist_style
= HI_STYLE_CLASSIC
;
3101 else /* Default to normal */
3102 hi
->userlist_style
= HI_STYLE_NORMAL
;
3103 } /* TODO: give error if unknow style is chosen */
3105 switch (hi
->userlist_style
) {
3106 case HI_STYLE_ADVANCED
:
3109 case HI_STYLE_CLASSIC
:
3112 case HI_STYLE_CLEAN
:
3115 case HI_STYLE_NORMAL
:
3120 reply("NSMSG_SET_STYLE", style
);
3124 static OPTION_FUNC(opt_announcements
)
3129 if (enabled_string(argv
[1]))
3130 hi
->announcements
= 'y';
3131 else if (disabled_string(argv
[1]))
3132 hi
->announcements
= 'n';
3133 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
3134 hi
->announcements
= '?';
3136 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
3141 switch (hi
->announcements
) {
3142 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
3143 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
3144 case '?': choice
= "default"; break;
3145 default: choice
= "unknown"; break;
3147 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
3151 static OPTION_FUNC(opt_password
)
3153 char crypted
[MD5_CRYPT_LENGTH
+1];
3158 reply("NSMSG_USE_CMD_PASS");
3162 cryptpass(argv
[1], crypted
);
3164 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3166 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
3167 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3172 strcpy(hi
->passwd
, crypted
);
3173 if (nickserv_conf
.sync_log
)
3174 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
3176 reply("NSMSG_SET_PASSWORD", "***");
3180 static OPTION_FUNC(opt_flags
)
3183 unsigned int ii
, flen
;
3186 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3191 nickserv_apply_flags(user
, hi
, argv
[1]);
3193 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
3194 if (hi
->flags
& (1 << ii
))
3195 flags
[flen
++] = handle_flags
[ii
];
3198 reply("NSMSG_SET_FLAGS", flags
);
3200 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
3204 static OPTION_FUNC(opt_email
)
3208 if (!valid_email(argv
[1])) {
3209 reply("NSMSG_BAD_EMAIL_ADDR");
3212 if ((str
= mail_prohibited_address(argv
[1]))) {
3213 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
3216 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
3217 reply("NSMSG_EMAIL_SAME");
3219 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
3222 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3224 if((rc
= ldap_do_modify(hi
->handle
, NULL
, argv
[1])) != LDAP_SUCCESS
) {
3225 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3230 nickserv_set_email_addr(hi
, argv
[1]);
3232 nickserv_eat_cookie(hi
->cookie
);
3233 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3236 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3240 static OPTION_FUNC(opt_maxlogins
)
3242 unsigned char maxlogins
;
3244 maxlogins
= strtoul(argv
[1], NULL
, 0);
3245 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
3246 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
3249 hi
->maxlogins
= maxlogins
;
3251 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
3252 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
3256 static OPTION_FUNC(opt_advanced
)
3259 if (enabled_string(argv
[1]))
3260 HANDLE_SET_FLAG(hi
, ADVANCED
);
3261 else if (disabled_string(argv
[1]))
3262 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
3264 reply("MSG_INVALID_BINARY", argv
[1]);
3269 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
3273 static OPTION_FUNC(opt_language
)
3275 struct language
*lang
;
3277 lang
= language_find(argv
[1]);
3278 if (irccasecmp(lang
->name
, argv
[1]))
3279 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
3280 hi
->language
= lang
;
3282 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
3286 static OPTION_FUNC(opt_karma
)
3289 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3294 if (argv
[1][0] == '+' && isdigit(argv
[1][1])) {
3295 hi
->karma
+= strtoul(argv
[1] + 1, NULL
, 10);
3296 } else if (argv
[1][0] == '-' && isdigit(argv
[1][1])) {
3297 hi
->karma
-= strtoul(argv
[1] + 1, NULL
, 10);
3299 send_message(user
, nickserv
, "NSMSG_INVALID_KARMA", argv
[1]);
3303 send_message(user
, nickserv
, "NSMSG_SET_KARMA", hi
->karma
);
3307 /* Called from opserv from cmd_access */
3309 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
3310 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
3312 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
3313 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
3314 && (user
->handle_info
->opserv_level
< 1000))) {
3315 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
3318 if ((user
->handle_info
->opserv_level
< new_level
)
3319 || ((user
->handle_info
->opserv_level
== new_level
)
3320 && (user
->handle_info
->opserv_level
< 1000))) {
3321 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
3324 if (user
->handle_info
== target
) {
3325 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
3329 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_oper_group_dn
) && *(nickserv_conf
.ldap_admin_dn
)) {
3331 if(new_level
> nickserv_conf
.ldap_oper_group_level
)
3332 rc
= ldap_add2group(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3334 rc
= ldap_delfromgroup(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3335 if(rc
!= LDAP_SUCCESS
&& rc
!= LDAP_TYPE_OR_VALUE_EXISTS
&& rc
!= LDAP_NO_SUCH_ATTRIBUTE
) {
3336 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3341 if (target
->opserv_level
== new_level
)
3343 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
3344 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
3345 target
->opserv_level
= new_level
;
3349 static OPTION_FUNC(opt_level
)
3354 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3358 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
3359 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
3363 static OPTION_FUNC(opt_epithet
)
3365 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
3367 struct userNode
*target
, *next_un
;
3370 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3374 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
3378 if ((epithet
[0] == '*') && !epithet
[1])
3381 hi
->epithet
= strdup(epithet
);
3383 for (target
= hi
->users
; target
; target
= next_un
) {
3384 irc_swhois(nickserv
, target
, hi
->epithet
);
3386 next_un
= target
->next_authed
;
3391 reply("NSMSG_SET_EPITHET", hi
->epithet
);
3393 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
3397 static OPTION_FUNC(opt_title
)
3403 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
3405 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3410 if(!strcmp(title
, "*")) {
3412 hi
->fakehost
= NULL
;
3415 if (strchr(title
, '.')) {
3416 reply("NSMSG_TITLE_INVALID");
3419 /* Alphanumeric titles only. */
3420 for(sptr
= title
; *sptr
; sptr
++) {
3421 if(!isalnum(*sptr
) && *sptr
!= '-') {
3422 reply("NSMSG_TITLE_INVALID");
3426 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
3427 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3428 reply("NSMSG_TITLE_TRUNCATED");
3432 hi
->fakehost
= malloc(strlen(title
)+2);
3433 hi
->fakehost
[0] = '.';
3434 strcpy(hi
->fakehost
+1, title
);
3437 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3438 title
= hi
->fakehost
+ 1;
3440 /* If theres no title set then the default title will therefore
3441 be the first part of hidden_host in x3.conf, so for
3442 consistency with opt_fakehost we will print this here.
3443 This isnt actually used in P10, its just handled to keep from crashing... */
3444 char *hs
, *hidden_suffix
, *rest
;
3446 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3447 hidden_suffix
= strdup(hs
);
3449 /* Yes we do this twice */
3450 if((rest
= strchr(hidden_suffix
, '.')))
3453 title
= hidden_suffix
;
3457 /* A lame default if someone configured hidden_host to something lame */
3458 title
= strdup("users");
3459 free(hidden_suffix
);
3465 none
= user_find_message(user
, "MSG_NONE");
3466 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3471 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3475 // check for a dot in the vhost
3476 if(strchr(vhost
, '.') == NULL
) {
3477 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3481 // check for a @ in the vhost
3482 if(strchr(vhost
, '@') != NULL
) {
3483 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3487 // check for denied words, inspired by monk at paki.sex
3488 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3489 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3490 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3495 // check for ircu's HOSTLEN length.
3496 if(strlen(vhost
) >= HOSTLEN
) {
3497 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3501 /* This can be handled by the regex now if desired.
3502 if (vhost[strspn(vhost, "0123456789.")]) {
3503 hostname = vhost + strlen(vhost);
3504 for (depth = 1; depth && (hostname > vhost); depth--) {
3506 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3509 if (*hostname == '.') hostname++; * advance past last dot we saw *
3510 if(strlen(hostname) > 4) {
3511 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3516 /* test either regex or as valid handle */
3517 if (nickserv_conf
.valid_fakehost_regex_set
) {
3518 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3521 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3522 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3524 if(err
== REG_NOMATCH
) {
3525 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3534 static OPTION_FUNC(opt_fakehost
)
3538 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3540 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3545 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3546 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3549 if (!strcmp(fake
, "*")) {
3552 hi
->fakehost
= NULL
;
3555 else if (!check_vhost(argv
[1], user
, cmd
)) {
3556 /* check_vhost takes care of error reply */
3562 hi
->fakehost
= strdup(fake
);
3565 fake
= hi
->fakehost
;
3567 fake
= generate_fakehost(hi
);
3569 /* Tell them we set the host */
3571 fake
= user_find_message(user
, "MSG_NONE");
3572 reply("NSMSG_SET_FAKEHOST", fake
);
3576 static OPTION_FUNC(opt_note
)
3579 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3584 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3589 if ((text
[0] == '*') && !text
[1])
3592 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3597 reply("NSMSG_SET_NOTE", hi
->note
? hi
->note
->note
: user_find_message(user
, "MSG_NONE"));
3601 static NICKSERV_FUNC(cmd_reclaim
)
3603 struct handle_info
*hi
;
3604 struct nick_info
*ni
;
3605 struct userNode
*victim
;
3607 NICKSERV_MIN_PARMS(2);
3608 hi
= user
->handle_info
;
3609 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3611 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3614 if (ni
->owner
!= user
->handle_info
) {
3615 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3618 victim
= GetUserH(ni
->nick
);
3620 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3623 if (victim
== user
) {
3624 reply("NSMSG_NICK_USER_YOU");
3627 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3628 switch (nickserv_conf
.reclaim_action
) {
3629 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3630 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3631 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3632 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3637 static NICKSERV_FUNC(cmd_unregnick
)
3640 struct handle_info
*hi
;
3641 struct nick_info
*ni
;
3643 hi
= user
->handle_info
;
3644 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3645 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3647 reply("NSMSG_UNKNOWN_NICK", nick
);
3650 if (hi
!= ni
->owner
) {
3651 reply("NSMSG_NOT_YOUR_NICK", nick
);
3654 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3659 static NICKSERV_FUNC(cmd_ounregnick
)
3661 struct nick_info
*ni
;
3663 NICKSERV_MIN_PARMS(2);
3664 if (!(ni
= get_nick_info(argv
[1]))) {
3665 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3668 if (!oper_outranks(user
, ni
->owner
))
3670 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3675 static NICKSERV_FUNC(cmd_unregister
)
3677 struct handle_info
*hi
;
3680 NICKSERV_MIN_PARMS(2);
3681 hi
= user
->handle_info
;
3684 if (checkpass(passwd
, hi
->passwd
)) {
3685 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3690 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3691 reply("NSMSG_PASSWORD_INVALID");
3696 static NICKSERV_FUNC(cmd_ounregister
)
3698 struct handle_info
*hi
;
3699 char reason
[MAXLEN
];
3702 NICKSERV_MIN_PARMS(2);
3703 if (!(hi
= get_victim_oper(user
, argv
[1])))
3706 if (HANDLE_FLAGGED(hi
, NODELETE
)) {
3707 reply("NSMSG_UNREGISTER_NODELETE", hi
->handle
);
3711 force
= IsOper(user
) && (argc
> 2) && !irccasecmp(argv
[2], "force");
3713 ((hi
->flags
& nickserv_conf
.ounregister_flags
)
3715 || (hi
->last_quit_host
[0] && ((unsigned)(now
- hi
->lastseen
) < nickserv_conf
.ounregister_inactive
)))) {
3716 reply((IsOper(user
) ? "NSMSG_UNREGISTER_MUST_FORCE" : "NSMSG_UNREGISTER_CANNOT_FORCE"), hi
->handle
);
3719 snprintf(reason
, sizeof(reason
), "%s unregistered account %s.", user
->handle_info
->handle
, hi
->handle
);
3720 global_message(MESSAGE_RECIPIENT_STAFF
, reason
);
3721 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3727 static NICKSERV_FUNC(cmd_status
)
3729 if (nickserv_conf
.disable_nicks
) {
3730 reply("NSMSG_GLOBAL_STATS_NONICK",
3731 dict_size(nickserv_handle_dict
));
3733 if (user
->handle_info
) {
3735 struct nick_info
*ni
;
3736 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3737 reply("NSMSG_HANDLE_STATS", cnt
);
3739 reply("NSMSG_HANDLE_NONE");
3741 reply("NSMSG_GLOBAL_STATS",
3742 dict_size(nickserv_handle_dict
),
3743 dict_size(nickserv_nick_dict
));
3748 static NICKSERV_FUNC(cmd_ghost
)
3750 struct userNode
*target
;
3751 char reason
[MAXLEN
];
3753 NICKSERV_MIN_PARMS(2);
3754 if (!(target
= GetUserH(argv
[1]))) {
3755 reply("MSG_NICK_UNKNOWN", argv
[1]);
3758 if (target
== user
) {
3759 reply("NSMSG_CANNOT_GHOST_SELF");
3762 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3763 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3766 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3767 DelUser(target
, nickserv
, 1, reason
);
3768 reply("NSMSG_GHOST_KILLED", argv
[1]);
3772 static NICKSERV_FUNC(cmd_vacation
)
3774 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3775 reply("NSMSG_ON_VACATION");
3780 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3782 struct handle_info
*hi
;
3785 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3787 saxdb_start_record(ctx
, iter_key(it
), 0);
3788 if (hi
->announcements
!= '?') {
3789 flags
[0] = hi
->announcements
;
3791 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3794 struct handle_cookie
*cookie
= hi
->cookie
;
3797 switch (cookie
->type
) {
3798 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3799 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3800 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3801 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3802 default: type
= NULL
; break;
3805 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3806 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3807 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3809 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3810 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3811 saxdb_end_record(ctx
);
3815 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3817 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3819 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3820 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3821 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3822 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3823 saxdb_end_record(ctx
);
3827 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3831 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3832 if (hi
->flags
& (1 << ii
))
3833 flags
[flen
++] = handle_flags
[ii
];
3835 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3838 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3839 if (hi
->last_quit_host
[0])
3840 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3841 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3843 saxdb_write_sint(ctx
, KEY_KARMA
, hi
->karma
);
3844 if (hi
->masks
->used
)
3845 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3846 if (hi
->ignores
->used
)
3847 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3849 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3851 struct string_list
*slist
;
3852 struct nick_info
*ni
;
3854 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3855 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3856 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3860 if (hi
->opserv_level
)
3861 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3862 if (hi
->language
!= lang_C
)
3863 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3864 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3865 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3866 if (hi
->screen_width
)
3867 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3868 if (hi
->table_width
)
3869 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3870 flags
[0] = hi
->userlist_style
;
3872 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3873 saxdb_end_record(ctx
);
3879 static handle_merge_func_t
*handle_merge_func_list
;
3880 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3883 reg_handle_merge_func(handle_merge_func_t func
)
3885 if (handle_merge_func_used
== handle_merge_func_size
) {
3886 if (handle_merge_func_size
) {
3887 handle_merge_func_size
<<= 1;
3888 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3890 handle_merge_func_size
= 8;
3891 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3894 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3897 static NICKSERV_FUNC(cmd_merge
)
3899 struct handle_info
*hi_from
, *hi_to
;
3900 struct userNode
*last_user
;
3901 struct userData
*cList
, *cListNext
;
3902 unsigned int ii
, jj
, n
;
3904 NICKSERV_MIN_PARMS(3);
3906 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3908 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3910 if (hi_to
== hi_from
) {
3911 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3915 for (n
=0; n
<handle_merge_func_used
; n
++)
3916 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3918 /* Append "from" handle's nicks to "to" handle's nick list. */
3920 struct nick_info
*last_ni
;
3921 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3922 last_ni
->next
= hi_from
->nicks
;
3924 while (hi_from
->nicks
) {
3925 hi_from
->nicks
->owner
= hi_to
;
3926 hi_from
->nicks
= hi_from
->nicks
->next
;
3929 /* Merge the hostmasks. */
3930 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3931 char *mask
= hi_from
->masks
->list
[ii
];
3932 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3933 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3935 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3936 string_list_append(hi_to
->masks
, strdup(mask
));
3939 /* Merge the ignores. */
3940 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3941 char *ignore
= hi_from
->ignores
->list
[ii
];
3942 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3943 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3945 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3946 string_list_append(hi_to
->ignores
, strdup(ignore
));
3949 /* Merge the lists of authed users. */
3951 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3952 last_user
->next_authed
= hi_from
->users
;
3954 hi_to
->users
= hi_from
->users
;
3956 /* Repoint the old "from" handle's users. */
3957 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3958 last_user
->handle_info
= hi_to
;
3960 hi_from
->users
= NULL
;
3962 /* Merge channel userlists. */
3963 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3964 struct userData
*cList2
;
3965 cListNext
= cList
->u_next
;
3966 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3967 if (cList
->channel
== cList2
->channel
)
3969 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3970 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
);
3971 /* keep cList2 in hi_to; remove cList from hi_from */
3972 del_channel_user(cList
, 1);
3975 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
);
3976 /* remove the lower-ranking cList2 from hi_to */
3977 del_channel_user(cList2
, 1);
3979 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3981 /* cList needs to be moved from hi_from to hi_to */
3982 cList
->handle
= hi_to
;
3983 /* Remove from linked list for hi_from */
3984 assert(!cList
->u_prev
);
3985 hi_from
->channels
= cList
->u_next
;
3987 cList
->u_next
->u_prev
= cList
->u_prev
;
3988 /* Add to linked list for hi_to */
3989 cList
->u_prev
= NULL
;
3990 cList
->u_next
= hi_to
->channels
;
3991 if (hi_to
->channels
)
3992 hi_to
->channels
->u_prev
= cList
;
3993 hi_to
->channels
= cList
;
3997 /* Do they get an OpServ level promotion? */
3998 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3999 hi_to
->opserv_level
= hi_from
->opserv_level
;
4001 /* What about last seen time? */
4002 if (hi_from
->lastseen
> hi_to
->lastseen
)
4003 hi_to
->lastseen
= hi_from
->lastseen
;
4005 /* New karma is the sum of the two original karmas. */
4006 hi_to
->karma
+= hi_from
->karma
;
4008 /* Does a fakehost carry over? (This intentionally doesn't set it
4009 * for users previously attached to hi_to. They'll just have to
4012 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
4013 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
4015 /* Notify of success. */
4016 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
4017 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
4018 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
4020 /* Unregister the "from" handle. */
4021 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
4022 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
4023 * the process isn't completed.
4029 struct nickserv_discrim
{
4030 unsigned long flags_on
, flags_off
;
4031 time_t min_registered
, max_registered
;
4034 int min_level
, max_level
;
4035 int min_karma
, max_karma
;
4036 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
4037 const char *nickmask
;
4038 const char *hostmask
;
4039 const char *handlemask
;
4040 const char *emailmask
;
4042 unsigned int inldap
;
4046 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
4048 struct discrim_apply_info
{
4049 struct nickserv_discrim
*discrim
;
4050 discrim_search_func func
;
4051 struct userNode
*source
;
4052 unsigned int matched
;
4055 static struct nickserv_discrim
*
4056 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
4059 struct nickserv_discrim
*discrim
;
4061 discrim
= malloc(sizeof(*discrim
));
4062 memset(discrim
, 0, sizeof(*discrim
));
4063 discrim
->min_level
= 0;
4064 discrim
->max_level
= INT_MAX
;
4065 discrim
->limit
= 50;
4066 discrim
->min_registered
= 0;
4067 discrim
->max_registered
= INT_MAX
;
4068 discrim
->lastseen
= LONG_MAX
;
4069 discrim
->min_karma
= INT_MIN
;
4070 discrim
->max_karma
= INT_MAX
;
4072 discrim
->inldap
= 2;
4075 for (i
=0; i
<argc
; i
++) {
4076 if (i
== argc
- 1) {
4077 reply("MSG_MISSING_PARAMS", argv
[i
]);
4080 if (!irccasecmp(argv
[i
], "limit")) {
4081 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
4082 } else if (!irccasecmp(argv
[i
], "flags")) {
4083 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
4084 } else if (!irccasecmp(argv
[i
], "registered")) {
4085 const char *cmp
= argv
[++i
];
4086 if (cmp
[0] == '<') {
4087 if (cmp
[1] == '=') {
4088 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
4090 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
4092 } else if (cmp
[0] == '=') {
4093 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
4094 } else if (cmp
[0] == '>') {
4095 if (cmp
[1] == '=') {
4096 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
4098 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
4101 reply("MSG_INVALID_CRITERIA", cmp
);
4103 } else if (!irccasecmp(argv
[i
], "seen")) {
4104 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
4105 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
4106 discrim
->nickmask
= argv
[++i
];
4107 } else if (!irccasecmp(argv
[i
], "hostmask")) {
4109 if (!irccasecmp(argv
[i
], "exact")) {
4110 if (i
== argc
- 1) {
4111 reply("MSG_MISSING_PARAMS", argv
[i
]);
4114 discrim
->hostmask_type
= EXACT
;
4115 } else if (!irccasecmp(argv
[i
], "subset")) {
4116 if (i
== argc
- 1) {
4117 reply("MSG_MISSING_PARAMS", argv
[i
]);
4120 discrim
->hostmask_type
= SUBSET
;
4121 } else if (!irccasecmp(argv
[i
], "superset")) {
4122 if (i
== argc
- 1) {
4123 reply("MSG_MISSING_PARAMS", argv
[i
]);
4126 discrim
->hostmask_type
= SUPERSET
;
4127 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
4128 if (i
== argc
- 1) {
4129 reply("MSG_MISSING_PARAMS", argv
[i
]);
4132 discrim
->hostmask_type
= LASTQUIT
;
4135 discrim
->hostmask_type
= SUPERSET
;
4137 discrim
->hostmask
= argv
[++i
];
4138 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask") || !irccasecmp(argv
[i
], "account")) {
4139 if (!irccasecmp(argv
[++i
], "*")) {
4140 discrim
->handlemask
= 0;
4142 discrim
->handlemask
= argv
[i
];
4144 } else if (!irccasecmp(argv
[i
], "email")) {
4145 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
4146 reply("MSG_NO_SEARCH_ACCESS", "email");
4148 } else if (!irccasecmp(argv
[++i
], "*")) {
4149 discrim
->emailmask
= 0;
4151 discrim
->emailmask
= argv
[i
];
4153 } else if (!irccasecmp(argv
[i
], "access")) {
4154 const char *cmp
= argv
[++i
];
4155 if (cmp
[0] == '<') {
4156 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
4157 if (cmp
[1] == '=') {
4158 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
4160 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
4162 } else if (cmp
[0] == '=') {
4163 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
4164 } else if (cmp
[0] == '>') {
4165 if (cmp
[1] == '=') {
4166 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
4168 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
4171 reply("MSG_INVALID_CRITERIA", cmp
);
4173 } else if (!irccasecmp(argv
[i
], "karma")) {
4174 const char *cmp
= argv
[++i
];
4175 if (cmp
[0] == '<') {
4176 if (cmp
[1] == '=') {
4177 discrim
->max_karma
= strtoul(cmp
+2, NULL
, 0);
4179 discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0) - 1;
4181 } else if (cmp
[0] == '=') {
4182 discrim
->min_karma
= discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0);
4183 } else if (cmp
[0] == '>') {
4184 if (cmp
[1] == '=') {
4185 discrim
->min_karma
= strtoul(cmp
+2, NULL
, 0);
4187 discrim
->min_karma
= strtoul(cmp
+1, NULL
, 0) + 1;
4190 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
4193 } else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[i
], "inldap")) {
4195 if(true_string(argv
[i
])) {
4196 discrim
->inldap
= 1;
4198 else if (false_string(argv
[i
])) {
4199 discrim
->inldap
= 0;
4202 reply("MSG_INVALID_BINARY", argv
[i
]);
4206 reply("MSG_INVALID_CRITERIA", argv
[i
]);
4217 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
4219 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
4220 || (discrim
->flags_off
& hi
->flags
)
4221 || (discrim
->min_registered
> hi
->registered
)
4222 || (discrim
->max_registered
< hi
->registered
)
4223 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
4224 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
4225 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
4226 || (discrim
->min_level
> hi
->opserv_level
)
4227 || (discrim
->max_level
< hi
->opserv_level
)
4228 || (discrim
->min_karma
> hi
->karma
)
4229 || (discrim
->max_karma
< hi
->karma
)
4233 if (discrim
->hostmask
) {
4235 for (i
=0; i
<hi
->masks
->used
; i
++) {
4236 const char *mask
= hi
->masks
->list
[i
];
4237 if ((discrim
->hostmask_type
== SUBSET
)
4238 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
4239 else if ((discrim
->hostmask_type
== EXACT
)
4240 && !irccasecmp(discrim
->hostmask
, mask
)) break;
4241 else if ((discrim
->hostmask_type
== SUPERSET
)
4242 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
4243 else if ((discrim
->hostmask_type
== LASTQUIT
)
4244 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
4246 if (i
==hi
->masks
->used
) return 0;
4248 if (discrim
->nickmask
) {
4249 struct nick_info
*nick
= hi
->nicks
;
4251 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
4254 if (!nick
) return 0;
4257 if(nickserv_conf
.ldap_enable
&& discrim
->inldap
!= 2) {
4259 rc
= ldap_get_user_info(hi
->handle
, NULL
);
4260 if(discrim
->inldap
== 1 && rc
!= LDAP_SUCCESS
)
4262 if(discrim
->inldap
== 0 && rc
== LDAP_SUCCESS
)
4271 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
4273 dict_iterator_t it
, next
;
4274 unsigned int matched
;
4276 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
4277 it
&& (matched
< discrim
->limit
);
4279 next
= iter_next(it
);
4280 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
4281 dsf(source
, iter_data(it
));
4289 search_print_func(struct userNode
*source
, struct handle_info
*match
)
4291 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
4295 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
4300 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
4302 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
4303 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
4308 search_add2ldap_func (struct userNode
*source
, struct handle_info
*match
)
4311 if(match
->email_addr
&& match
->passwd
&& match
->handle
) {
4312 rc
= ldap_do_add(match
->handle
, match
->passwd
, match
->email_addr
);
4313 if(rc
!= LDAP_SUCCESS
) {
4314 send_message(source
, nickserv
, "NSMSG_LDAP_FAIL_ADD", match
->handle
, ldap_err2string(rc
));
4321 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
4323 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
4324 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
4325 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
4326 return hi_b
->opserv_level
- hi_a
->opserv_level
;
4327 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
4331 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
4333 struct handle_info_list hil
;
4334 struct helpfile_table tbl
;
4339 memset(&hil
, 0, sizeof(hil
));
4340 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
4341 struct handle_info
*hi
= iter_data(it
);
4342 if (hi
->opserv_level
)
4343 handle_info_list_append(&hil
, hi
);
4345 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
4346 tbl
.length
= hil
.used
+ 1;
4348 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
4349 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
4350 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4353 for (ii
= 0; ii
< hil
.used
; ) {
4354 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4355 ary
[0] = hil
.list
[ii
]->handle
;
4356 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
4357 tbl
.contents
[++ii
] = ary
;
4359 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4360 /*reply("MSG_MATCH_COUNT", hil.used); */
4361 for (ii
= 0; ii
< hil
.used
; ii
++)
4362 free(tbl
.contents
[ii
]);
4367 static NICKSERV_FUNC(cmd_search
)
4369 struct nickserv_discrim
*discrim
;
4370 discrim_search_func action
;
4371 struct svccmd
*subcmd
;
4372 unsigned int matches
;
4375 NICKSERV_MIN_PARMS(3);
4376 sprintf(buf
, "search %s", argv
[1]);
4377 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
4378 if (!irccasecmp(argv
[1], "print"))
4379 action
= search_print_func
;
4380 else if (!irccasecmp(argv
[1], "count"))
4381 action
= search_count_func
;
4382 else if (!irccasecmp(argv
[1], "unregister"))
4383 action
= search_unregister_func
;
4385 else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[1], "add2ldap"))
4386 action
= search_add2ldap_func
;
4389 reply("NSMSG_INVALID_ACTION", argv
[1]);
4393 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
4396 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
4400 if (action
== search_print_func
)
4401 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4402 else if (action
== search_count_func
)
4403 discrim
->limit
= INT_MAX
;
4405 matches
= nickserv_discrim_search(discrim
, action
, user
);
4408 reply("MSG_MATCH_COUNT", matches
);
4410 reply("MSG_NO_MATCHES");
4416 static MODCMD_FUNC(cmd_checkpass
)
4418 struct handle_info
*hi
;
4420 NICKSERV_MIN_PARMS(3);
4421 if (!(hi
= get_handle_info(argv
[1]))) {
4422 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
4425 if (checkpass(argv
[2], hi
->passwd
))
4426 reply("CHECKPASS_YES");
4428 reply("CHECKPASS_NO");
4433 static MODCMD_FUNC(cmd_checkemail
)
4435 struct handle_info
*hi
;
4437 NICKSERV_MIN_PARMS(3);
4438 if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
4441 if (!hi
->email_addr
)
4442 reply("CHECKEMAIL_NOT_SET");
4443 else if (!irccasecmp(argv
[2], hi
->email_addr
))
4444 reply("CHECKEMAIL_YES");
4446 reply("CHECKEMAIL_NO");
4451 nickserv_db_read_handle(char *handle
, dict_t obj
)
4454 struct string_list
*masks
, *slist
, *ignores
;
4455 struct handle_info
*hi
;
4456 struct userNode
*authed_users
;
4457 struct userData
*channel_list
;
4458 unsigned long int id
;
4461 char *setter
, *note
;
4464 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
4465 id
= str
? strtoul(str
, NULL
, 0) : 0;
4466 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
4468 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
4471 if ((hi
= get_handle_info(handle
))) {
4472 authed_users
= hi
->users
;
4473 channel_list
= hi
->channels
;
4475 hi
->channels
= NULL
;
4476 dict_remove(nickserv_handle_dict
, hi
->handle
);
4478 authed_users
= NULL
;
4479 channel_list
= NULL
;
4481 if(nickserv_conf
.force_handles_lowercase
)
4482 irc_strtolower(handle
);
4483 hi
= register_handle(handle
, str
, id
);
4485 hi
->users
= authed_users
;
4486 while (authed_users
) {
4487 authed_users
->handle_info
= hi
;
4488 authed_users
= authed_users
->next_authed
;
4491 hi
->channels
= channel_list
;
4492 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
4493 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
4494 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
4495 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
4496 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
4497 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
4498 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
4499 hi
->language
= language_find(str
? str
: "C");
4500 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
4501 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
4502 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
4504 hi
->infoline
= strdup(str
);
4505 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
4506 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4507 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
4508 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
4509 str
= database_get_data(obj
, KEY_KARMA
, RECDB_QSTRING
);
4510 hi
->karma
= str
? strtoul(str
, NULL
, 0) : 0;
4511 /* We want to read the nicks even if disable_nicks is set. This is so
4512 * that we don't lose the nick data entirely. */
4513 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
4515 for (ii
=0; ii
<slist
->used
; ii
++)
4516 register_nick(slist
->list
[ii
], hi
);
4518 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
4520 for (ii
=0; str
[ii
]; ii
++)
4521 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
4523 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
4524 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4525 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
4526 hi
->announcements
= str
? str
[0] : '?';
4527 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
4528 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
4529 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
4530 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
4531 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
4533 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
4535 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
4536 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
4538 nickserv_set_email_addr(hi
, str
);
4539 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
4541 hi
->epithet
= strdup(str
);
4542 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
4544 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
4545 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
4546 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4547 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
4548 if (setter
&& date
&& note
)
4550 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
4555 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
4557 hi
->fakehost
= strdup(str
);
4559 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4561 const char *data
, *type
, *expires
, *cookie_str
;
4562 struct handle_cookie
*cookie
;
4564 cookie
= calloc(1, sizeof(*cookie
));
4565 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4566 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4567 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4568 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4569 if (!type
|| !expires
|| !cookie_str
) {
4570 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4573 if (!irccasecmp(type
, KEY_ACTIVATION
))
4574 cookie
->type
= ACTIVATION
;
4575 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4576 cookie
->type
= PASSWORD_CHANGE
;
4577 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4578 cookie
->type
= EMAIL_CHANGE
;
4579 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4580 cookie
->type
= ALLOWAUTH
;
4582 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4585 cookie
->expires
= strtoul(expires
, NULL
, 0);
4586 if (cookie
->expires
< now
)
4589 cookie
->data
= strdup(data
);
4590 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4594 nickserv_bake_cookie(cookie
);
4596 nickserv_free_cookie(cookie
);
4601 nickserv_saxdb_read(dict_t db
) {
4603 struct record_data
*rd
;
4606 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4608 handle
= strdup(iter_key(it
));
4609 nickserv_db_read_handle(handle
, rd
->d
.object
);
4615 static NICKSERV_FUNC(cmd_mergedb
)
4617 struct timeval start
, stop
;
4620 NICKSERV_MIN_PARMS(2);
4621 gettimeofday(&start
, NULL
);
4622 if (!(db
= parse_database(argv
[1]))) {
4623 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4626 nickserv_saxdb_read(db
);
4628 gettimeofday(&stop
, NULL
);
4629 stop
.tv_sec
-= start
.tv_sec
;
4630 stop
.tv_usec
-= start
.tv_usec
;
4631 if (stop
.tv_usec
< 0) {
4633 stop
.tv_usec
+= 1000000;
4635 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4640 expire_handles(UNUSED_ARG(void *data
))
4642 dict_iterator_t it
, next
;
4644 struct handle_info
*hi
;
4646 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4647 next
= iter_next(it
);
4649 if ((hi
->opserv_level
> 0)
4651 || HANDLE_FLAGGED(hi
, FROZEN
)
4652 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4655 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4656 if ((now
- hi
->lastseen
) > expiry
) {
4657 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4658 nickserv_unregister_handle(hi
, NULL
, NULL
);
4662 if (nickserv_conf
.handle_expire_frequency
)
4663 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4667 nickserv_load_dict(const char *fname
)
4671 if (!(file
= fopen(fname
, "r"))) {
4672 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4675 while (fgets(line
, sizeof(line
), file
)) {
4678 if (line
[strlen(line
)-1] == '\n')
4679 line
[strlen(line
)-1] = 0;
4680 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4683 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4686 static enum reclaim_action
4687 reclaim_action_from_string(const char *str
) {
4689 return RECLAIM_NONE
;
4690 else if (!irccasecmp(str
, "warn"))
4691 return RECLAIM_WARN
;
4692 else if (!irccasecmp(str
, "svsnick"))
4693 return RECLAIM_SVSNICK
;
4694 else if (!irccasecmp(str
, "kill"))
4695 return RECLAIM_KILL
;
4697 return RECLAIM_NONE
;
4701 nickserv_conf_read(void)
4703 dict_t conf_node
, child
;
4706 struct string_list
*strlist
;
4708 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4709 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4712 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4714 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4715 if (nickserv_conf
.valid_handle_regex_set
)
4716 regfree(&nickserv_conf
.valid_handle_regex
);
4718 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4719 nickserv_conf
.valid_handle_regex_set
= !err
;
4720 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4722 nickserv_conf
.valid_handle_regex_set
= 0;
4724 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4725 if (nickserv_conf
.valid_nick_regex_set
)
4726 regfree(&nickserv_conf
.valid_nick_regex
);
4728 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4729 nickserv_conf
.valid_nick_regex_set
= !err
;
4730 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4732 nickserv_conf
.valid_nick_regex_set
= 0;
4734 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4735 if (nickserv_conf
.valid_fakehost_regex_set
)
4736 regfree(&nickserv_conf
.valid_fakehost_regex
);
4738 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4739 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4740 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4742 nickserv_conf
.valid_fakehost_regex_set
= 0;
4744 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4746 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4747 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4748 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4749 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4750 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4751 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4752 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4753 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4754 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4755 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4756 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4757 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4758 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4759 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4760 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4761 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4762 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4763 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4764 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4765 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4766 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4767 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4768 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4769 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4770 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4772 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4773 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4774 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4776 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4777 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4778 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4780 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4781 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4782 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4783 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4784 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4785 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4786 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4787 str
= database_get_data(conf_node
, KEY_OUNREGISTER_INACTIVE
, RECDB_QSTRING
);
4788 nickserv_conf
.ounregister_inactive
= str
? ParseInterval(str
) : 86400*28;
4789 str
= database_get_data(conf_node
, KEY_OUNREGISTER_FLAGS
, RECDB_QSTRING
);
4792 nickserv_conf
.ounregister_flags
= 0;
4794 unsigned int pos
= handle_inverse_flags
[(unsigned char)*str
];
4797 nickserv_conf
.ounregister_flags
|= 1 << (pos
- 1);
4799 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4800 if (!nickserv_conf
.disable_nicks
) {
4801 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4802 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4803 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4804 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4805 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4806 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4807 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4808 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4810 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4811 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4812 const char *key
= iter_key(it
), *value
;
4816 if (!strncasecmp(key
, "uc_", 3))
4817 flag
= toupper(key
[3]);
4818 else if (!strncasecmp(key
, "lc_", 3))
4819 flag
= tolower(key
[3]);
4823 if ((pos
= handle_inverse_flags
[flag
])) {
4824 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4825 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4828 if (nickserv_conf
.weak_password_dict
)
4829 dict_delete(nickserv_conf
.weak_password_dict
);
4830 nickserv_conf
.weak_password_dict
= dict_new();
4831 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4832 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4833 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4834 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4836 nickserv_load_dict(str
);
4837 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4838 if (nickserv
&& str
)
4839 NickChange(nickserv
, str
, 0);
4840 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4841 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4842 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4843 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4844 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4845 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4846 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4847 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4848 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4849 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4850 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4851 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4852 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4853 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4854 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4855 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4856 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4857 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4858 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4859 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4861 free_string_list(nickserv_conf
.denied_fakehost_words
);
4862 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4864 strlist
= string_list_copy(strlist
);
4866 strlist
= alloc_string_list(4);
4867 string_list_append(strlist
, strdup("sex"));
4868 string_list_append(strlist
, strdup("fuck"));
4870 nickserv_conf
.denied_fakehost_words
= strlist
;
4872 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4873 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4875 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4876 nickserv_conf
.auto_oper
= str
? str
: "";
4878 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4879 nickserv_conf
.auto_admin
= str
? str
: "";
4881 str
= conf_get_data("server/network", RECDB_QSTRING
);
4882 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4883 if (!nickserv_conf
.auth_policer_params
) {
4884 nickserv_conf
.auth_policer_params
= policer_params_new();
4885 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4886 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4888 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4889 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4890 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4892 str
= database_get_data(conf_node
, KEY_LDAP_ENABLE
, RECDB_QSTRING
);
4893 nickserv_conf
.ldap_enable
= str
? strtoul(str
, NULL
, 0) : 0;
4895 str
= database_get_data(conf_node
, KEY_FORCE_HANDLES_LOWERCASE
, RECDB_QSTRING
);
4896 nickserv_conf
.force_handles_lowercase
= str
? strtol(str
, NULL
, 0) : 0;
4899 if(nickserv_conf
.ldap_enable
> 0) {
4900 /* ldap is enabled but not compiled in - error out */
4901 log_module(MAIN_LOG
, LOG_ERROR
, "ldap is enabled in config, but not compiled in!");
4902 nickserv_conf
.ldap_enable
= 0;
4908 str
= database_get_data(conf_node
, KEY_LDAP_URI
, RECDB_QSTRING
);
4909 nickserv_conf
.ldap_uri
= str
? str
: "";
4911 str
= database_get_data(conf_node
, KEY_LDAP_BASE
, RECDB_QSTRING
);
4912 nickserv_conf
.ldap_base
= str
? str
: "";
4914 str
= database_get_data(conf_node
, KEY_LDAP_DN_FMT
, RECDB_QSTRING
);
4915 nickserv_conf
.ldap_dn_fmt
= str
? str
: "";
4917 str
= database_get_data(conf_node
, KEY_LDAP_VERSION
, RECDB_QSTRING
);
4918 nickserv_conf
.ldap_version
= str
? strtoul(str
, NULL
, 0) : 3;
4920 str
= database_get_data(conf_node
, KEY_LDAP_AUTOCREATE
, RECDB_QSTRING
);
4921 nickserv_conf
.ldap_autocreate
= str
? strtoul(str
, NULL
, 0) : 0;
4923 str
= database_get_data(conf_node
, KEY_LDAP_TIMEOUT
, RECDB_QSTRING
);
4924 nickserv_conf
.ldap_timeout
= str
? strtoul(str
, NULL
, 0) : 5;
4926 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_DN
, RECDB_QSTRING
);
4927 nickserv_conf
.ldap_admin_dn
= str
? str
: "";
4929 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_PASS
, RECDB_QSTRING
);
4930 nickserv_conf
.ldap_admin_pass
= str
? str
: "";
4932 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_ACCOUNT
, RECDB_QSTRING
);
4933 nickserv_conf
.ldap_field_account
= str
? str
: "";
4935 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_PASSWORD
, RECDB_QSTRING
);
4936 nickserv_conf
.ldap_field_password
= str
? str
: "";
4938 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_EMAIL
, RECDB_QSTRING
);
4939 nickserv_conf
.ldap_field_email
= str
? str
: "";
4941 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_DN
, RECDB_QSTRING
);
4942 nickserv_conf
.ldap_oper_group_dn
= str
? str
: "";
4944 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_LEVEL
, RECDB_QSTRING
);
4945 nickserv_conf
.ldap_oper_group_level
= str
? strtoul(str
, NULL
, 0) : 99;
4947 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_GROUP_MEMBER
, RECDB_QSTRING
);
4948 nickserv_conf
.ldap_field_group_member
= str
? str
: "";
4950 free_string_list(nickserv_conf
.ldap_object_classes
);
4951 strlist
= database_get_data(conf_node
, KEY_LDAP_OBJECT_CLASSES
, RECDB_STRING_LIST
);
4953 strlist
= string_list_copy(strlist
);
4955 strlist
= alloc_string_list(4);
4956 string_list_append(strlist
, strdup("top"));
4958 nickserv_conf
.ldap_object_classes
= strlist
;
4965 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4967 char newnick
[NICKLEN
+1];
4976 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4978 case RECLAIM_SVSNICK
:
4980 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4981 } while (GetUserH(newnick
));
4982 irc_svsnick(nickserv
, user
, newnick
);
4985 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4986 DelUser(user
, nickserv
, 1, msg
);
4992 nickserv_reclaim_p(void *data
) {
4993 struct userNode
*user
= data
;
4994 struct nick_info
*ni
= get_nick_info(user
->nick
);
4996 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5000 check_user_nick(struct userNode
*user
) {
5001 struct nick_info
*ni
;
5002 user
->modes
&= ~FLAGS_REGNICK
;
5003 if (!(ni
= get_nick_info(user
->nick
)))
5005 if (user
->handle_info
== ni
->owner
) {
5006 user
->modes
|= FLAGS_REGNICK
;
5010 if (nickserv_conf
.warn_nick_owned
)
5011 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
5012 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
5014 if (nickserv_conf
.auto_reclaim_delay
)
5015 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
5017 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5023 handle_account(struct userNode
*user
, const char *stamp
)
5025 struct handle_info
*hi
;
5028 #ifdef WITH_PROTOCOL_P10
5029 time_t timestamp
= 0;
5031 colon
= strchr(stamp
, ':');
5032 if(colon
&& colon
[1])
5035 timestamp
= atoi(colon
+1);
5037 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
5038 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
5040 log_module(MAIN_LOG
, LOG_WARNING
, "%s using account %s but timestamp does not match %s is not %s.", user
->nick
, stamp
, ctime(×tamp
),
5041 ctime(&hi
->registered
));
5045 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
5046 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
5050 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
5053 set_user_handle_info(user
, hi
, 0);
5055 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
5060 handle_nick_change(struct userNode
*user
, const char *old_nick
)
5062 struct handle_info
*hi
;
5064 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
5065 dict_remove(nickserv_allow_auth_dict
, old_nick
);
5066 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
5068 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5069 check_user_nick(user
);
5073 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
5075 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
5076 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5077 set_user_handle_info(user
, NULL
, 0);
5080 static struct modcmd
*
5081 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
5083 if (min_level
> 0) {
5085 sprintf(buf
, "%u", min_level
);
5086 if (must_be_qualified
) {
5087 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
5089 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
5091 } else if (min_level
== 0) {
5092 if (must_be_qualified
) {
5093 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5095 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5098 if (must_be_qualified
) {
5099 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
5101 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
5107 nickserv_db_cleanup(void)
5109 unreg_del_user_func(nickserv_remove_user
);
5110 userList_clean(&curr_helpers
);
5111 policer_params_delete(nickserv_conf
.auth_policer_params
);
5112 dict_delete(nickserv_handle_dict
);
5113 dict_delete(nickserv_nick_dict
);
5114 dict_delete(nickserv_opt_dict
);
5115 dict_delete(nickserv_allow_auth_dict
);
5116 dict_delete(nickserv_email_dict
);
5117 dict_delete(nickserv_id_dict
);
5118 dict_delete(nickserv_conf
.weak_password_dict
);
5119 free(auth_func_list
);
5120 free(unreg_func_list
);
5122 free(allowauth_func_list
);
5123 free(handle_merge_func_list
);
5124 free(failpw_func_list
);
5125 if (nickserv_conf
.valid_handle_regex_set
)
5126 regfree(&nickserv_conf
.valid_handle_regex
);
5127 if (nickserv_conf
.valid_nick_regex_set
)
5128 regfree(&nickserv_conf
.valid_nick_regex
);
5131 void handle_loc_auth_oper(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
)) {
5132 if (!*nickserv_conf
.auto_oper
|| !user
->handle_info
)
5135 if (!IsOper(user
)) {
5136 if (*nickserv_conf
.auto_admin
&& user
->handle_info
->opserv_level
>= opserv_conf_admin_level()) {
5137 irc_umode(user
, nickserv_conf
.auto_admin
);
5138 irc_sno(0x1, "%s (%s@%s) is now an IRC Administrator",
5139 user
->nick
, user
->ident
, user
->hostname
);
5140 } else if (*nickserv_conf
.auto_oper
&& user
->handle_info
->opserv_level
) {
5141 irc_umode(user
, nickserv_conf
.auto_oper
);
5142 irc_sno(0x1, "%s (%s@%s) is now an IRC Operator",
5143 user
->nick
, user
->ident
, user
->hostname
);
5149 init_nickserv(const char *nick
)
5151 struct chanNode
*chan
;
5153 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
5154 reg_new_user_func(check_user_nick
);
5155 reg_nick_change_func(handle_nick_change
);
5156 reg_del_user_func(nickserv_remove_user
);
5157 reg_account_func(handle_account
);
5158 reg_auth_func(handle_loc_auth_oper
);
5160 /* set up handle_inverse_flags */
5161 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
5162 for (i
=0; handle_flags
[i
]; i
++) {
5163 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
5164 flag_access_levels
[i
] = 0;
5167 conf_register_reload(nickserv_conf_read
);
5168 nickserv_opt_dict
= dict_new();
5169 nickserv_email_dict
= dict_new();
5171 dict_set_free_keys(nickserv_email_dict
, free
);
5172 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
5174 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
5175 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
5176 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
5177 * a big pain to disable since its nolonger in the config file. ) -Rubin
5179 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
5180 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
5181 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
5182 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
5183 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
5184 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
5185 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
5186 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
5187 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
5188 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
5189 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
5190 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
5191 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
5192 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
5193 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
5194 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
5195 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
5196 nickserv_define_func("MERGE", cmd_merge
, 750, 1, 0);
5197 if (!nickserv_conf
.disable_nicks
) {
5198 /* nick management commands */
5199 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
5200 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
5201 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
5202 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
5203 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
5204 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
5206 if (nickserv_conf
.email_enabled
) {
5207 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
5208 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
5209 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
5210 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
5211 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
5212 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
5214 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
5215 /* ignore commands */
5216 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
5217 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
5218 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
5219 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
5220 /* miscellaneous commands */
5221 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
5222 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
5223 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
5224 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
5225 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
5226 nickserv_define_func("CHECKEMAIL", cmd_checkemail
, 0, 1, 0);
5228 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
5229 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
5230 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
5231 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
5232 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
5233 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
5234 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
5235 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
5236 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
5237 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
5238 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
5239 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
5240 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
5241 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
5242 if (nickserv_conf
.titlehost_suffix
) {
5243 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
5244 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
5246 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
5247 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
5248 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
5249 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
5250 dict_insert(nickserv_opt_dict
, "KARMA", opt_karma
);
5252 nickserv_handle_dict
= dict_new();
5253 dict_set_free_keys(nickserv_handle_dict
, free
);
5254 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
5256 nickserv_id_dict
= dict_new();
5257 dict_set_free_keys(nickserv_id_dict
, free
);
5259 nickserv_nick_dict
= dict_new();
5260 dict_set_free_data(nickserv_nick_dict
, free
);
5262 nickserv_allow_auth_dict
= dict_new();
5264 userList_init(&curr_helpers
);
5267 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
5268 nickserv
= AddLocalUser(nick
, nick
, NULL
, "Nick Services", modes
);
5269 nickserv_service
= service_register(nickserv
);
5271 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
5272 reg_exit_func(nickserv_db_cleanup
);
5273 if(nickserv_conf
.handle_expire_frequency
)
5274 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
5276 if(autojoin_channels
&& nickserv
) {
5277 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
5278 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
5279 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
5283 ldap_do_init(nickserv_conf
);
5286 message_register_table(msgtab
);