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"
84 #define KEY_PASSWD "passwd"
85 #define KEY_NICKS "nicks"
86 #define KEY_MASKS "masks"
87 #define KEY_IGNORES "ignores"
88 #define KEY_OPSERV_LEVEL "opserv_level"
89 #define KEY_FLAGS "flags"
90 #define KEY_REGISTER_ON "register"
91 #define KEY_LAST_SEEN "lastseen"
92 #define KEY_INFO "info"
93 #define KEY_USERLIST_STYLE "user_style"
94 #define KEY_SCREEN_WIDTH "screen_width"
95 #define KEY_LAST_AUTHED_HOST "last_authed_host"
96 #define KEY_LAST_QUIT_HOST "last_quit_host"
97 #define KEY_EMAIL_ADDR "email_addr"
98 #define KEY_COOKIE "cookie"
99 #define KEY_COOKIE_DATA "data"
100 #define KEY_COOKIE_TYPE "type"
101 #define KEY_COOKIE_EXPIRES "expires"
102 #define KEY_ACTIVATION "activation"
103 #define KEY_PASSWORD_CHANGE "password change"
104 #define KEY_EMAIL_CHANGE "email change"
105 #define KEY_ALLOWAUTH "allowauth"
106 #define KEY_EPITHET "epithet"
107 #define KEY_TABLE_WIDTH "table_width"
108 #define KEY_ANNOUNCEMENTS "announcements"
109 #define KEY_MAXLOGINS "maxlogins"
110 #define KEY_FAKEHOST "fakehost"
111 #define KEY_NOTE_NOTE "note"
112 #define KEY_NOTE_SETTER "setter"
113 #define KEY_NOTE_DATE "date"
114 #define KEY_FORCE_HANDLES_LOWERCASE "force_handles_lowercase"
116 #define KEY_LDAP_ENABLE "ldap_enable"
119 #define KEY_LDAP_URI "ldap_uri"
120 #define KEY_LDAP_BASE "ldap_base"
121 #define KEY_LDAP_DN_FMT "ldap_dn_fmt"
122 #define KEY_LDAP_VERSION "ldap_version"
123 #define KEY_LDAP_AUTOCREATE "ldap_autocreate"
124 #define KEY_LDAP_ADMIN_DN "ldap_admin_dn"
125 #define KEY_LDAP_ADMIN_PASS "ldap_admin_pass"
126 #define KEY_LDAP_FIELD_ACCOUNT "ldap_field_account"
127 #define KEY_LDAP_FIELD_PASSWORD "ldap_field_password"
128 #define KEY_LDAP_FIELD_EMAIL "ldap_field_email"
129 #define KEY_LDAP_OBJECT_CLASSES "ldap_object_classes"
130 #define KEY_LDAP_OPER_GROUP_DN "ldap_oper_group_dn"
131 #define KEY_LDAP_OPER_GROUP_LEVEL "ldap_oper_group_level"
132 #define KEY_LDAP_FIELD_GROUP_MEMBER "ldap_field_group_member"
133 #define KEY_LDAP_TIMEOUT "ldap_timeout"
136 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
138 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
139 #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[])
140 typedef OPTION_FUNC(option_func_t
);
142 DEFINE_LIST(handle_info_list
, struct handle_info
*);
144 #define NICKSERV_MIN_PARMS(N) do { \
146 reply("MSG_MISSING_PARAMS", argv[0]); \
147 svccmd_send_help_brief(user, nickserv, cmd); \
151 struct userNode
*nickserv
;
152 struct userList curr_helpers
;
153 const char *handle_flags
= HANDLE_FLAGS
;
155 extern struct string_list
*autojoin_channels
;
156 static struct module *nickserv_module
;
157 static struct service
*nickserv_service
;
158 static struct log_type
*NS_LOG
;
159 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
160 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
161 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
162 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
163 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
164 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
165 static char handle_inverse_flags
[256];
166 static unsigned int flag_access_levels
[32];
167 static const struct message_entry msgtab
[] = {
168 { "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." },
169 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
170 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu characters or less."},
171 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
172 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
173 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
174 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
175 { "NSMSG_LDAP_FAIL", "There was a problem in contacting the account server (ldap): %s. Please try again later." },
176 { "NSMSG_LDAP_FAIL_ADD", "There was a problem in adding account %s to ldap: %s." },
177 { "NSMSG_LDAP_FAIL_SEND_EMAIL", "There was a problem in storing your email address in the account server (ldap): %s. Please try again later." },
178 { "NSMSG_LDAP_FAIL_GET_EMAIL", "There was a problem in retrieving your email address from the account server (ldap): %s. Please try again later." },
179 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
180 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
181 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
182 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
183 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
184 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
185 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
186 { "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." },
187 { "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." },
188 { "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." },
189 { "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." },
190 { "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." },
191 { "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." },
192 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
193 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
194 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
195 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
196 { "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." },
197 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
198 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
199 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
200 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
201 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
202 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
203 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
204 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
205 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
206 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
207 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
208 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
209 { "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 *@*)." },
210 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
211 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
212 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
213 { "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)" },
214 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
215 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
216 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
217 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
218 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
219 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
220 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
221 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
222 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
223 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
224 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
225 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
226 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
227 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
228 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
229 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
230 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
231 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
232 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
233 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
234 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
235 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
236 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
237 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
238 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
239 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
240 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
241 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
242 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
243 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
244 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
245 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
246 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
247 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
248 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
249 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
250 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
251 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
252 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
253 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
254 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
255 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
256 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
257 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
258 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
259 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
260 { "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)." },
261 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
262 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
263 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
264 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
265 { "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." },
266 { "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." },
267 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
268 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
269 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
270 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
271 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
272 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
273 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
274 { "NSMSG_PASS_SUCCESS", "Password changed." },
275 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
276 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
277 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
278 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
279 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
280 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
281 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
282 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
283 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
284 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
285 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
286 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
287 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
288 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
289 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
290 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
291 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
292 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
293 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
294 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
295 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
296 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
297 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
298 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
299 { "NSMSG_NO_ACCESS", "Access denied." },
300 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
301 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
302 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
303 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
304 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
305 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
306 { "NSMSG_BAD_HANDLE", "Account $b%s$b is not allowed because it is reserved, is too long, or contains invalid characters." },
307 { "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." },
308 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
309 { "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." },
310 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
311 { "NSMSG_SEARCH_MATCH", "Match: %s" },
312 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
313 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
314 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
315 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
316 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
317 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
318 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
319 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
320 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
321 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
322 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
323 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
324 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
325 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
326 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
327 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
328 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
329 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
330 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
331 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
332 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
333 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
334 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
335 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
336 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
337 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
338 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
339 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
340 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
341 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
342 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
343 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
344 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
345 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
347 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
348 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
350 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
351 { "NSEMAIL_ACTIVATION_BODY",
352 "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"
354 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
355 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
356 "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"
357 "/msg %3$s@%4$s AUTH %5$s your-password\n"
358 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
359 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
361 "If you did NOT request this account, you do not need to do anything.\n"
362 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
363 { "NSEMAIL_ACTIVATION_BODY_WEB",
364 "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"
366 "To verify your email address and complete the account registration, visit the following URL:\n"
367 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
369 "If you did NOT request this account, you do not need to do anything.\n"
370 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
371 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
372 { "NSEMAIL_PASSWORD_CHANGE_BODY",
373 "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"
374 "To complete the password change, log on to %1$s and type the following command:\n"
375 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
376 "If you did NOT request your password to be changed, you do not need to do anything.\n"
377 "Please contact the %1$s staff if you have questions." },
378 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
379 "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"
380 "To complete the password change, click the following URL:\n"
381 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
382 "If you did NOT request your password to be changed, you do not need to do anything.\n"
383 "Please contact the %1$s staff if you have questions." },
384 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
385 #ifdef stupid_verify_old_email
386 { "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." },
387 { "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." },
389 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
390 { "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." },
391 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
392 { "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." },
393 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
394 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
395 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
396 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
397 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
398 { "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." },
399 { "CHECKPASS_YES", "Yes." },
400 { "CHECKPASS_NO", "No." },
401 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
405 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
406 static void nickserv_reclaim_p(void *data
);
408 struct nickserv_config nickserv_conf
;
410 /* We have 2^32 unique account IDs to use. */
411 unsigned long int highest_id
= 0;
414 canonicalize_hostmask(char *mask
)
416 char *out
= mask
, *temp
;
417 if ((temp
= strchr(mask
, '!'))) {
419 while (*temp
) *out
++ = *temp
++;
425 static struct handle_note
*
426 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
428 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
430 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
432 memcpy(note
->note
, text
, strlen(text
));
436 static struct handle_info
*
437 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
439 struct handle_info
*hi
;
441 hi
= calloc(1, sizeof(*hi
));
442 hi
->userlist_style
= nickserv_conf
.default_style
? nickserv_conf
.default_style
: HI_DEFAULT_STYLE
;
443 hi
->announcements
= '?';
444 hi
->handle
= strdup(handle
);
445 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
447 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
453 register_nick(const char *nick
, struct handle_info
*owner
)
455 struct nick_info
*ni
;
456 ni
= malloc(sizeof(struct nick_info
));
457 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
459 ni
->next
= owner
->nicks
;
461 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
465 delete_nick(struct nick_info
*ni
)
467 struct nick_info
*last
, *next
;
468 struct userNode
*user
;
469 /* Check to see if we should mark a user as unregistered. */
470 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
471 user
->modes
&= ~FLAGS_REGNICK
;
474 /* Remove ni from the nick_info linked list. */
475 if (ni
== ni
->owner
->nicks
) {
476 ni
->owner
->nicks
= ni
->next
;
478 last
= ni
->owner
->nicks
;
484 last
->next
= next
->next
;
486 dict_remove(nickserv_nick_dict
, ni
->nick
);
489 static unreg_func_t
*unreg_func_list
;
490 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
493 reg_unreg_func(unreg_func_t func
)
495 if (unreg_func_used
== unreg_func_size
) {
496 if (unreg_func_size
) {
497 unreg_func_size
<<= 1;
498 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
501 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
504 unreg_func_list
[unreg_func_used
++] = func
;
508 nickserv_free_cookie(void *data
)
510 struct handle_cookie
*cookie
= data
;
511 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
512 if (cookie
->data
) free(cookie
->data
);
517 free_handle_info(void *vhi
)
519 struct handle_info
*hi
= vhi
;
521 free_string_list(hi
->masks
);
522 free_string_list(hi
->ignores
);
526 delete_nick(hi
->nicks
);
532 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
533 nickserv_free_cookie(hi
->cookie
);
535 if (hi
->email_addr
) {
536 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
537 handle_info_list_remove(hil
, hi
);
539 dict_remove(nickserv_email_dict
, hi
->email_addr
);
544 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
547 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
550 struct userNode
*uNode
;
553 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
555 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
556 if( (rc
= ldap_delete_account(hi
->handle
)) != LDAP_SUCCESS
) {
558 send_message(notify
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
560 if(rc
!= LDAP_NO_SUCH_OBJECT
)
561 return false; /* if theres noone there to delete, its kinda ok, right ?:) */
566 for (n
=0; n
<unreg_func_used
; n
++)
567 unreg_func_list
[n
](notify
, hi
);
569 if (nickserv_conf
.sync_log
) {
570 uNode
= GetUserH(hi
->users
->nick
);
574 set_user_handle_info(hi
->users
, NULL
, 0);
577 if (nickserv_conf
.disable_nicks
)
578 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
580 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
583 if (nickserv_conf
.sync_log
)
584 SyncLog("UNREGISTER %s", hi
->handle
);
586 dict_remove(nickserv_handle_dict
, hi
->handle
);
591 get_handle_info(const char *handle
)
593 return dict_find(nickserv_handle_dict
, handle
, 0);
597 get_nick_info(const char *nick
)
599 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
603 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
608 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
609 mn
= channel
->members
.list
[nn
];
610 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
617 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
618 if (!user
->handle_info
) {
620 send_message(user
, bot
, "MSG_AUTHENTICATE");
624 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
626 send_message(user
, bot
, "NSMSG_NO_ACCESS");
630 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
632 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
636 if (user
->handle_info
->opserv_level
< min_level
) {
638 send_message(user
, bot
, "NSMSG_NO_ACCESS");
646 is_valid_handle(const char *handle
)
648 struct userNode
*user
;
649 /* cant register a juped nick/service nick as handle, to prevent confusion */
650 user
= GetUserH(handle
);
651 if (user
&& IsLocal(user
))
653 /* check against maximum length */
654 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
656 /* for consistency, only allow account names that could be nicks */
657 if (!is_valid_nick(handle
))
659 /* disallow account names that look like bad words */
660 if (opserv_bad_channel(handle
))
662 /* test either regex or containing all valid chars */
663 if (nickserv_conf
.valid_handle_regex_set
) {
664 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
667 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
668 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
672 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
677 is_registerable_nick(const char *nick
)
679 struct userNode
*user
;
680 /* cant register a juped nick/service nick as nick, to prevent confusion */
681 user
= GetUserH(nick
);
682 if (user
&& IsLocal(user
))
684 /* for consistency, only allow nicks names that could be nicks */
685 if (!is_valid_nick(nick
))
687 /* disallow nicks that look like bad words */
688 if (opserv_bad_channel(nick
))
691 if (strlen(nick
) > NICKLEN
)
693 /* test either regex or as valid handle */
694 if (nickserv_conf
.valid_nick_regex_set
) {
695 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
698 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
699 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
705 /* this has been replaced with one in tools.c
708 is_valid_email_addr(const char *email)
710 return strchr(email, '@') != NULL;
716 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
718 if (hi
->email_addr
) {
719 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
720 return hi
->email_addr
;
730 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
732 struct handle_info
*hi
;
733 struct userNode
*target
;
737 if (!(hi
= get_handle_info(++name
))) {
738 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
743 if (!(target
= GetUserH(name
))) {
744 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
747 if (IsLocal(target
)) {
748 if (IsService(target
))
749 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
751 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
754 if (!(hi
= target
->handle_info
)) {
755 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
763 oper_outranks(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
) {
764 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
766 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
767 if ((user
->handle_info
->opserv_level
== 1000)
768 || (user
->handle_info
== hi
)
769 || ((user
->handle_info
->opserv_level
== 0)
770 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
771 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
775 reply("MSG_USER_OUTRANKED", hi
->handle
);
780 get_victim_oper(struct svccmd
*cmd
, struct userNode
*user
, const char *target
)
782 struct handle_info
*hi
;
783 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
785 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
786 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
789 return oper_outranks(cmd
, user
, hi
) ? hi
: NULL
;
793 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
797 /* If no hostmasks on the account, allow it. */
798 if (!hi
->masks
->used
)
800 /* If any hostmask matches, allow it. */
801 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
802 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
804 /* If they are allowauthed to this account, allow it (removing the aa). */
805 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
806 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
809 /* The user is not allowed to use this account. */
814 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
817 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
821 if (len
< nickserv_conf
.password_min_length
) {
823 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
826 if (!irccasecmp(pass
, handle
)) {
828 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
831 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
834 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
837 for (i
=0; i
<len
; i
++) {
838 if (isdigit(pass
[i
]))
840 if (isupper(pass
[i
]))
842 if (islower(pass
[i
]))
845 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
846 || (cnt_upper
< nickserv_conf
.password_min_upper
)
847 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
849 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
855 static auth_func_t
*auth_func_list
;
856 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
859 reg_auth_func(auth_func_t func
)
861 if (auth_func_used
== auth_func_size
) {
862 if (auth_func_size
) {
863 auth_func_size
<<= 1;
864 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
867 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
870 auth_func_list
[auth_func_used
++] = func
;
873 static handle_rename_func_t
*rf_list
;
874 static unsigned int rf_list_size
, rf_list_used
;
877 reg_handle_rename_func(handle_rename_func_t func
)
879 if (rf_list_used
== rf_list_size
) {
882 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
885 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
888 rf_list
[rf_list_used
++] = func
;
892 generate_fakehost(struct handle_info
*handle
)
894 struct userNode
*target
;
895 extern const char *hidden_host_suffix
;
896 static char buffer
[HOSTLEN
+1];
900 if (!handle
->fakehost
) {
901 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
906 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
907 else if (style
== 2) {
908 /* Due to the way fakehost is coded theres no way i can
909 get the exact user, so for now ill just take the first
911 for (target
= handle
->users
; target
; target
= target
->next_authed
)
914 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
917 } else if (handle
->fakehost
[0] == '.') {
918 /* A leading dot indicates the stored value is actually a title. */
919 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
922 return handle
->fakehost
;
926 apply_fakehost(struct handle_info
*handle
)
928 struct userNode
*target
;
933 fake
= generate_fakehost(handle
);
934 for (target
= handle
->users
; target
; target
= target
->next_authed
)
935 assign_fakehost(target
, fake
, 1);
938 void send_func_list(struct userNode
*user
)
941 struct handle_info
*old_info
;
943 old_info
= user
->handle_info
;
945 for (n
=0; n
<auth_func_used
; n
++)
946 auth_func_list
[n
](user
, old_info
);
950 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
953 struct handle_info
*old_info
;
955 /* This can happen if somebody uses COOKIE while authed, or if
956 * they re-auth to their current handle (which is silly, but users
958 if (user
->handle_info
== hi
)
961 if (user
->handle_info
) {
962 struct userNode
*other
;
965 userList_remove(&curr_helpers
, user
);
967 /* remove from next_authed linked list */
968 if (user
->handle_info
->users
== user
) {
969 user
->handle_info
->users
= user
->next_authed
;
971 for (other
= user
->handle_info
->users
;
972 other
->next_authed
!= user
;
973 other
= other
->next_authed
) ;
974 other
->next_authed
= user
->next_authed
;
976 /* if nobody left on old handle, and they're not an oper, remove !god */
977 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
978 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
979 /* record them as being last seen at this time */
980 user
->handle_info
->lastseen
= now
;
981 /* and record their hostmask */
982 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
984 old_info
= user
->handle_info
;
985 user
->handle_info
= hi
;
986 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
987 HANDLE_CLEAR_FLAG(hi
, HELPING
);
989 /* Call auth handlers */
990 if (!GetUserH(user
->nick
))
994 struct nick_info
*ni
;
996 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
997 if (nickserv_conf
.warn_clone_auth
) {
998 struct userNode
*other
;
999 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1000 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1003 /* Add this auth to users list of current auths */
1004 user
->next_authed
= hi
->users
;
1007 /* Add to helpers list */
1009 userList_append(&curr_helpers
, user
);
1011 /* Set the fakehost */
1012 if (hi
->fakehost
|| old_info
)
1016 #ifdef WITH_PROTOCOL_P10
1017 /* Stamp users with their account name. */
1018 char *id
= hi
->handle
;
1020 const char *id
= "???";
1022 /* Mark all the nicks registered to this
1023 * account as registered nicks
1024 * - Why not just this one? -rubin */
1025 if (!nickserv_conf
.disable_nicks
) {
1026 struct nick_info
*ni
;
1027 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1028 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1029 user
->modes
|= FLAGS_REGNICK
;
1034 /* send the account to the ircd */
1035 StampUser(user
, id
, hi
->registered
);
1038 /* Stop trying to kick this user off their nick */
1039 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1040 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1042 /* We cannot clear the user's account ID, unfortunately. */
1043 user
->next_authed
= NULL
;
1046 /* Call auth handlers */
1047 if (GetUserH(user
->nick
)) {
1048 for (n
=0; n
<auth_func_used
; n
++)
1049 auth_func_list
[n
](user
, old_info
);
1053 static struct handle_info
*
1054 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1056 struct handle_info
*hi
;
1057 struct nick_info
*ni
;
1058 char crypted
[MD5_CRYPT_LENGTH
];
1060 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1062 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1066 if(strlen(handle
) > 30)
1069 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 30);
1073 if (!is_secure_password(handle
, passwd
, user
))
1076 cryptpass(passwd
, crypted
);
1078 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1080 rc
= ldap_do_add(handle
, crypted
, NULL
);
1081 if(LDAP_SUCCESS
!= rc
&& LDAP_ALREADY_EXISTS
!= rc
) {
1083 send_message(user
, nickserv
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1088 hi
= register_handle(handle
, crypted
, 0);
1089 hi
->masks
= alloc_string_list(1);
1090 hi
->ignores
= alloc_string_list(1);
1092 hi
->language
= lang_C
;
1093 hi
->registered
= now
;
1095 hi
->flags
= HI_DEFAULT_FLAGS
;
1096 if (settee
&& !no_auth
)
1097 set_user_handle_info(settee
, hi
, 1);
1099 if (user
!= settee
) {
1101 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1103 else if (nickserv_conf
.disable_nicks
) {
1105 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1108 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
))) {
1110 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1115 if (is_registerable_nick(user
->nick
)) {
1116 register_nick(user
->nick
, hi
);
1117 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1121 if (settee
&& (user
!= settee
)) {
1123 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1130 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1132 cookie
->hi
->cookie
= cookie
;
1133 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1136 /* Contributed by the great sneep of afternet ;) */
1137 /* Since this gets used in a URL, we want to avoid stuff that confuses
1138 * email clients such as ] and ?. a-z, 0-9 only.
1140 void genpass(char *str
, int len
)
1145 for(i
= 0; i
< len
; i
++)
1149 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1150 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1158 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1160 struct handle_cookie
*cookie
;
1161 char subject
[128], body
[4096], *misc
;
1162 const char *netname
, *fmt
;
1166 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1170 cookie
= calloc(1, sizeof(*cookie
));
1172 cookie
->type
= type
;
1173 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1175 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1176 /* Adding dedicated password gen function for more control -Rubin */
1177 genpass(cookie
->cookie
, 10);
1179 *inttobase64(cookie->cookie, rand(), 5);
1180 *inttobase64(cookie->cookie+5, rand(), 5);
1183 netname
= nickserv_conf
.network_name
;
1186 switch (cookie
->type
) {
1188 hi
->passwd
[0] = 0; /* invalidate password */
1189 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1190 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1191 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1194 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1196 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1198 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1201 case PASSWORD_CHANGE
:
1202 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1203 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1204 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1206 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1208 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1209 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1213 misc
= hi
->email_addr
;
1214 hi
->email_addr
= cookie
->data
;
1215 #ifdef stupid_verify_old_email
1217 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1218 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1219 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1220 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1221 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1222 sendmail(nickserv
, hi
, subject
, body
, 1);
1223 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1224 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1228 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1229 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1230 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1231 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1232 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1233 sendmail(nickserv
, hi
, subject
, body
, 1);
1235 #ifdef stupid_verify_old_email
1238 hi
->email_addr
= misc
;
1241 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1242 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1243 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1244 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1245 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1248 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1252 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1253 nickserv_bake_cookie(cookie
);
1257 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1259 cookie
->hi
->cookie
= NULL
;
1260 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1261 nickserv_free_cookie(cookie
);
1265 nickserv_free_email_addr(void *data
)
1267 handle_info_list_clean(data
);
1272 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1274 struct handle_info_list
*hil
;
1275 /* Remove from old handle_info_list ... */
1276 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1277 handle_info_list_remove(hil
, hi
);
1278 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1279 hi
->email_addr
= NULL
;
1281 /* Add to the new list.. */
1282 if (new_email_addr
) {
1283 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1284 hil
= calloc(1, sizeof(*hil
));
1285 hil
->tag
= strdup(new_email_addr
);
1286 handle_info_list_init(hil
);
1287 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1289 handle_info_list_append(hil
, hi
);
1290 hi
->email_addr
= hil
->tag
;
1294 static NICKSERV_FUNC(cmd_register
)
1297 struct handle_info
*hi
;
1298 const char *email_addr
, *password
;
1299 char syncpass
[MD5_CRYPT_LENGTH
];
1300 int no_auth
, weblink
;
1302 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1303 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1307 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1308 /* Require the first handle registered to belong to someone +o. */
1309 reply("NSMSG_REQUIRE_OPER");
1313 if (user
->handle_info
) {
1314 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1318 if (IsRegistering(user
)) {
1319 reply("NSMSG_ALREADY_REGISTERING");
1323 if (IsStamped(user
)) {
1324 /* Unauthenticated users might still have been stamped
1325 previously and could therefore have a hidden host;
1326 do not allow them to register a new account. */
1327 reply("NSMSG_STAMPED_REGISTER");
1331 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1333 if(nickserv_conf
.force_handles_lowercase
)
1334 irc_strtolower(argv
[1]);
1335 if (!is_valid_handle(argv
[1])) {
1336 reply("NSMSG_BAD_HANDLE", argv
[1]);
1341 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1342 struct handle_info_list
*hil
;
1345 /* Remember email address. */
1346 email_addr
= argv
[3];
1348 /* Check that the email address looks valid.. */
1349 if (!valid_email(email_addr
)) {
1350 reply("NSMSG_BAD_EMAIL_ADDR");
1354 /* .. and that we are allowed to send to it. */
1355 if ((str
= sendmail_prohibited_address(email_addr
))) {
1356 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1360 /* If we do email verify, make sure we don't spam the address. */
1361 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1363 for (nn
=0; nn
<hil
->used
; nn
++) {
1364 if (hil
->list
[nn
]->cookie
) {
1365 reply("NSMSG_EMAIL_UNACTIVATED");
1369 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1370 reply("NSMSG_EMAIL_OVERUSED");
1383 /* Webregister hack - send URL instead of IRC cookie
1386 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1390 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1392 /* Add any masks they should get. */
1393 if (nickserv_conf
.default_hostmask
) {
1394 string_list_append(hi
->masks
, strdup("*@*"));
1396 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1397 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1398 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1401 /* If they're the first to register, give them level 1000. */
1402 if (dict_size(nickserv_handle_dict
) == 1) {
1403 hi
->opserv_level
= 1000;
1404 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1407 /* Set their email address. */
1410 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1412 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email_addr
)) != LDAP_SUCCESS
) {
1413 /* Falied to update email in ldap, but still
1414 * updated it here.. what should we do? */
1415 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1417 nickserv_set_email_addr(hi
, email_addr
);
1421 nickserv_set_email_addr(hi
, email_addr
);
1424 nickserv_set_email_addr(hi
, email_addr
);
1428 /* If they need to do email verification, tell them. */
1430 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1432 /* Set registering flag.. */
1433 user
->modes
|= FLAGS_REGISTERING
;
1435 if (nickserv_conf
.sync_log
) {
1436 cryptpass(password
, syncpass
);
1438 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1439 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1442 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1445 /* this wont work if email is required .. */
1446 process_adduser_pending(user
);
1451 static NICKSERV_FUNC(cmd_oregister
)
1453 struct userNode
*settee
= NULL
;
1454 struct handle_info
*hi
;
1455 char* account
= NULL
;
1461 NICKSERV_MIN_PARMS(3);
1465 if(nickserv_conf
.force_handles_lowercase
)
1466 irc_strtolower(account
);
1467 if (nickserv_conf
.email_required
) {
1468 NICKSERV_MIN_PARMS(4);
1470 if (argc
>= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1471 if (strchr(argv
[4], '@') || argc
>= 6) /* If @, its mask not nick */
1481 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1482 if (strchr(argv
[3], '@') || argc
>= 5) /* If @, its mask not nick */
1491 /* If they passed a nick, look for that user.. */
1492 if (nick
&& !(settee
= GetUserH(nick
))) {
1493 reply("MSG_NICK_UNKNOWN", argv
[4]);
1496 /* If the setee is already authed, we cant add a 2nd account for them.. */
1497 if (settee
&& settee
->handle_info
) {
1498 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1501 /* If there is no default mask in the conf, and they didn't pass a mask,
1502 * but we did find a user by nick, generate the mask */
1504 if (nickserv_conf
.default_hostmask
)
1507 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1509 reply("NSMSG_REGISTER_BAD_NICKMASK");
1514 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1515 return 0; /* error reply handled by above */
1519 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1521 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email
)) != LDAP_SUCCESS
) {
1522 /* Falied to update email in ldap, but still
1523 * updated it here.. what should we do? */
1524 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1526 nickserv_set_email_addr(hi
, email
);
1530 nickserv_set_email_addr(hi
, email
);
1533 nickserv_set_email_addr(hi
, email
);
1537 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1538 string_list_append(hi
->masks
, mask_canonicalized
);
1541 if (nickserv_conf
.sync_log
)
1542 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1547 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1550 struct userNode
*target
;
1551 char *new_mask
= strdup(pretty_mask(mask
));
1552 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1553 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1554 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1559 string_list_append(hi
->ignores
, new_mask
);
1560 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1562 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1563 irc_silence(target
, new_mask
, 1);
1568 static NICKSERV_FUNC(cmd_addignore
)
1570 NICKSERV_MIN_PARMS(2);
1572 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1575 static NICKSERV_FUNC(cmd_oaddignore
)
1577 struct handle_info
*hi
;
1579 NICKSERV_MIN_PARMS(3);
1580 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1583 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1587 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1590 struct userNode
*target
;
1591 char *pmask
= strdup(pretty_mask(del_mask
));
1592 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1593 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1594 char *old_mask
= hi
->ignores
->list
[i
];
1595 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1596 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1597 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1598 irc_silence(target
, old_mask
, 0);
1605 reply("NSMSG_DELMASK_NOT_FOUND");
1609 static NICKSERV_FUNC(cmd_delignore
)
1611 NICKSERV_MIN_PARMS(2);
1612 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1615 static NICKSERV_FUNC(cmd_odelignore
)
1617 struct handle_info
*hi
;
1618 NICKSERV_MIN_PARMS(3);
1619 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1621 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1624 static NICKSERV_FUNC(cmd_handleinfo
)
1627 unsigned int i
, pos
=0, herelen
;
1628 struct userNode
*target
, *next_un
;
1629 struct handle_info
*hi
;
1630 const char *nsmsg_none
;
1633 if (!(hi
= user
->handle_info
)) {
1634 reply("NSMSG_MUST_AUTH");
1637 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1641 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1642 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1644 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1647 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1648 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1650 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1653 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1654 if (HANDLE_FLAGGED(hi
, FROZEN
))
1655 reply("NSMSG_HANDLEINFO_VACATION");
1657 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1658 struct do_not_register
*dnr
;
1659 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1660 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1661 if (!oper_outranks(cmd
, user
, hi
))
1663 } else if (hi
!= user
->handle_info
) {
1664 reply("NSMSG_HANDLEINFO_END");
1668 if (nickserv_conf
.email_enabled
)
1669 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1673 switch (hi
->cookie
->type
) {
1674 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1675 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1676 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1677 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1678 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1684 unsigned long flen
= 1;
1685 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1687 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1688 if (hi
->flags
& 1 << i
)
1689 flags
[flen
++] = handle_flags
[i
];
1691 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1693 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1696 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1697 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1698 || (hi
->opserv_level
> 0)) {
1699 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1702 if (IsHelping(user
) || IsOper(user
))
1707 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1708 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1713 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1715 if (hi
->last_quit_host
[0])
1716 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1718 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1720 if (nickserv_conf
.disable_nicks
) {
1721 /* nicks disabled; don't show anything about registered nicks */
1722 } else if (hi
->nicks
) {
1723 struct nick_info
*ni
, *next_ni
;
1724 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1725 herelen
= strlen(ni
->nick
);
1726 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1728 goto print_nicks_buff
;
1732 memcpy(buff
+pos
, ni
->nick
, herelen
);
1733 pos
+= herelen
; buff
[pos
++] = ' ';
1737 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1742 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1745 if (hi
->masks
->used
) {
1746 for (i
=0; i
< hi
->masks
->used
; i
++) {
1747 herelen
= strlen(hi
->masks
->list
[i
]);
1748 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1750 goto print_mask_buff
;
1752 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1753 pos
+= herelen
; buff
[pos
++] = ' ';
1754 if (i
+1 == hi
->masks
->used
) {
1757 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1762 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1765 if (hi
->ignores
->used
) {
1766 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1767 herelen
= strlen(hi
->ignores
->list
[i
]);
1768 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1770 goto print_ignore_buff
;
1772 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1773 pos
+= herelen
; buff
[pos
++] = ' ';
1774 if (i
+1 == hi
->ignores
->used
) {
1777 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1782 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1786 struct userData
*channel
, *next
;
1789 for (channel
= hi
->channels
; channel
; channel
= next
) {
1790 next
= channel
->u_next
;
1791 name
= channel
->channel
->channel
->name
;
1792 herelen
= strlen(name
);
1793 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1795 goto print_chans_buff
;
1797 if (IsUserSuspended(channel
))
1799 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1803 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1808 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1811 for (target
= hi
->users
; target
; target
= next_un
) {
1812 herelen
= strlen(target
->nick
);
1813 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1815 goto print_cnick_buff
;
1817 next_un
= target
->next_authed
;
1819 memcpy(buff
+pos
, target
->nick
, herelen
);
1820 pos
+= herelen
; buff
[pos
++] = ' ';
1824 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1829 reply("NSMSG_HANDLEINFO_END");
1833 static NICKSERV_FUNC(cmd_userinfo
)
1835 struct userNode
*target
;
1837 NICKSERV_MIN_PARMS(2);
1838 if (!(target
= GetUserH(argv
[1]))) {
1839 reply("MSG_NICK_UNKNOWN", argv
[1]);
1842 if (target
->handle_info
)
1843 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1845 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1849 static NICKSERV_FUNC(cmd_nickinfo
)
1851 struct nick_info
*ni
;
1853 NICKSERV_MIN_PARMS(2);
1854 if (!(ni
= get_nick_info(argv
[1]))) {
1855 reply("MSG_NICK_UNKNOWN", argv
[1]);
1858 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1862 static NICKSERV_FUNC(cmd_rename_handle
)
1864 struct handle_info
*hi
;
1865 struct userNode
*uNode
;
1869 NICKSERV_MIN_PARMS(3);
1870 if(nickserv_conf
.force_handles_lowercase
)
1871 irc_strtolower(argv
[2]);
1872 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1874 if (!is_valid_handle(argv
[2])) {
1875 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1878 if (get_handle_info(argv
[2])) {
1879 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1882 if(strlen(argv
[2]) > 30)
1884 reply("NMSG_HANDLE_TOLONG", argv
[2], 30);
1888 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1890 if( (rc
= ldap_rename_account(hi
->handle
, argv
[2])) != LDAP_SUCCESS
) {
1891 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1897 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1898 hi
->handle
= strdup(argv
[2]);
1899 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1900 for (nn
=0; nn
<rf_list_used
; nn
++)
1901 rf_list
[nn
](hi
, old_handle
);
1903 if (nickserv_conf
.sync_log
) {
1904 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1905 irc_rename(uNode
, hi
->handle
);
1907 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1910 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1911 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1912 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1918 static failpw_func_t
*failpw_func_list
;
1919 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1922 reg_failpw_func(failpw_func_t func
)
1924 if (failpw_func_used
== failpw_func_size
) {
1925 if (failpw_func_size
) {
1926 failpw_func_size
<<= 1;
1927 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1929 failpw_func_size
= 8;
1930 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1933 failpw_func_list
[failpw_func_used
++] = func
;
1937 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1939 * called by nefariouses enhanced AC login-on-connect code
1942 struct handle_info
*loc_auth(char *handle
, char *password
, char *userhost
)
1944 int pw_arg
, used
, maxlogins
;
1947 struct handle_info
*hi
;
1948 struct userNode
*other
;
1950 int ldap_result
= LDAP_SUCCESS
;
1954 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1958 if(nickserv_conf
.ldap_enable
) {
1959 ldap_result
= ldap_check_auth(handle
, password
);
1960 if(ldap_result
!= LDAP_SUCCESS
) {
1969 if (!checkpass(password
, hi
->passwd
)) {
1974 /* ldap libs are present but we are not using them... */
1975 if( !nickserv_conf
.ldap_enable
) {
1979 if (!checkpass(password
, hi
->passwd
)) {
1983 else if( (!hi
) && ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
1984 /* user not found, but authed to ldap successfully..
1985 * create the account.
1990 /* Add a *@* mask */
1991 /* TODO if userhost is not null, build mask based on that. */
1992 if(nickserv_conf
.default_hostmask
)
1995 return NULL
; /* They dont have a *@* mask so they can't loc */
1997 if(!(hi
= nickserv_register(NULL
, NULL
, handle
, password
, 0))) {
1998 return 0; /* couldn't add the user for some reason */
2001 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2003 if(nickserv_conf
.email_required
) {
2008 nickserv_set_email_addr(hi
, email
);
2012 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2013 string_list_append(hi
->masks
, mask_canonicalized
);
2015 if(nickserv_conf
.sync_log
)
2016 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, "@", handle
);
2020 /* Still no account, so just fail out */
2025 /* We don't know the users hostname, or anything because they
2026 * havn't registered yet. So we can only allow LOC if your
2027 * account has *@* as a hostmask.
2029 * UPDATE: New nefarious LOC supports u@h
2039 buf
= strdup(userhost
);
2040 ident
= mysep(&buf
, "@");
2041 realhost
= mysep(&buf
, ":");
2042 ip
= mysep(&buf
, ":");
2043 if(!ip
|| !realhost
|| !ident
) {
2045 return NULL
; /* Invalid AC request, just quit */
2047 uh
= malloc(strlen(userhost
));
2048 ui
= malloc(strlen(userhost
));
2049 sprintf(uh
, "%s@%s", ident
, realhost
);
2050 sprintf(ui
, "%s@%s", ident
, ip
);
2051 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2053 if(match_ircglob(uh
, hi
->masks
->list
[ii
])
2054 || match_ircglob(ui
, hi
->masks
->list
[ii
]))
2066 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2068 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
2078 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2082 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2083 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2084 if (++used
>= maxlogins
) {
2088 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2092 static NICKSERV_FUNC(cmd_auth
)
2094 int pw_arg
, used
, maxlogins
;
2095 struct handle_info
*hi
;
2097 struct userNode
*other
;
2099 int ldap_result
= LDAP_OTHER
;
2103 if (user
->handle_info
) {
2104 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2107 if (IsStamped(user
)) {
2108 /* Unauthenticated users might still have been stamped
2109 previously and could therefore have a hidden host;
2110 do not allow them to authenticate. */
2111 reply("NSMSG_STAMPED_AUTH");
2116 if(strchr(argv
[1], '<') || strchr(argv
[1], '>')) {
2117 reply("NSMSG_NO_ANGLEBRACKETS");
2120 if (!is_valid_handle(argv
[1])) {
2121 reply("NSMSG_BAD_HANDLE", argv
[1]);
2125 if(nickserv_conf
.ldap_enable
) {
2126 ldap_result
= ldap_check_auth(argv
[1], argv
[2]);
2127 /* Get the users email address and update it */
2128 if(ldap_result
== LDAP_SUCCESS
) {
2130 if((rc
= ldap_get_user_info(argv
[1], &email
) != LDAP_SUCCESS
))
2132 if(nickserv_conf
.email_required
) {
2133 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc
));
2138 else if(ldap_result
!= LDAP_INVALID_CREDENTIALS
) {
2139 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2145 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
2147 } else if (argc
== 2 && !nickserv_conf
.ldap_enable
) {
2148 if (nickserv_conf
.disable_nicks
) {
2149 if (!(hi
= get_handle_info(user
->nick
))) {
2150 reply("NSMSG_HANDLE_NOT_FOUND");
2154 /* try to look up their handle from their nick */
2155 /* TODO: handle ldap auth on nickserv style networks, too */
2156 struct nick_info
*ni
;
2157 ni
= get_nick_info(user
->nick
);
2159 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
2166 reply("MSG_MISSING_PARAMS", argv
[0]);
2167 svccmd_send_help_brief(user
, nickserv
, cmd
);
2172 if(nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2173 /* user not found, but authed to ldap successfully..
2174 * create the account.
2177 if(!(hi
= nickserv_register(user
, NULL
, argv
[1], argv
[2], 0))) {
2178 reply("NSMSG_UNABLE_TO_ADD");
2179 return 0; /* couldn't add the user for some reason */
2181 /* Add a *@* mask */
2182 if(nickserv_conf
.default_hostmask
)
2185 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2188 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2189 string_list_append(hi
->masks
, mask_canonicalized
);
2192 nickserv_set_email_addr(hi
, email
);
2195 if(nickserv_conf
.sync_log
)
2196 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
);
2200 reply("NSMSG_HANDLE_NOT_FOUND");
2206 /* Responses from here on look up the language used by the handle they asked about. */
2207 passwd
= argv
[pw_arg
];
2208 if (!valid_user_for(user
, hi
)) {
2209 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
2210 send_message_type(4, user
, cmd
->parent
->bot
,
2211 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
2214 send_message_type(4, user
, cmd
->parent
->bot
,
2215 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
2217 argv
[pw_arg
] = "BADMASK";
2221 if( ( nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_INVALID_CREDENTIALS
) ||
2222 ( (!nickserv_conf
.ldap_enable
) && (!checkpass(passwd
, hi
->passwd
)) ) ) {
2224 if (!checkpass(passwd
, hi
->passwd
)) {
2227 send_message_type(4, user
, cmd
->parent
->bot
,
2228 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
2229 argv
[pw_arg
] = "BADPASS";
2230 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
2231 if (nickserv_conf
.autogag_enabled
) {
2232 if (!user
->auth_policer
.params
) {
2233 user
->auth_policer
.last_req
= now
;
2234 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
2236 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
2238 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
2239 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
2240 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2242 argv
[pw_arg
] = "GAGGED";
2247 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2248 send_message_type(4, user
, cmd
->parent
->bot
,
2249 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2250 argv
[pw_arg
] = "SUSPENDED";
2253 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2254 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2255 if (++used
>= maxlogins
) {
2256 send_message_type(4, user
, cmd
->parent
->bot
,
2257 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2259 argv
[pw_arg
] = "MAXLOGINS";
2264 set_user_handle_info(user
, hi
, 1);
2265 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2266 reply("NSMSG_PLEASE_SET_EMAIL");
2267 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2268 reply("NSMSG_WEAK_PASSWORD");
2269 if (hi
->passwd
[0] != '$')
2270 cryptpass(passwd
, hi
->passwd
);
2272 /* If a channel was waiting for this user to auth,
2273 * finish adding them */
2274 process_adduser_pending(user
);
2276 reply("NSMSG_AUTH_SUCCESS");
2279 /* Set +x if autohide is on */
2280 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2281 irc_umode(user
, "+x");
2283 if(!IsOper(user
)) /* If they arnt already opered.. */
2285 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2286 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2288 irc_umode(user
,nickserv_conf
.auto_admin
);
2289 reply("NSMSG_AUTO_OPER_ADMIN");
2291 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2293 irc_umode(user
,nickserv_conf
.auto_oper
);
2294 reply("NSMSG_AUTO_OPER");
2298 /* Wipe out the pass for the logs */
2299 argv
[pw_arg
] = "****";
2303 static allowauth_func_t
*allowauth_func_list
;
2304 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2307 reg_allowauth_func(allowauth_func_t func
)
2309 if (allowauth_func_used
== allowauth_func_size
) {
2310 if (allowauth_func_size
) {
2311 allowauth_func_size
<<= 1;
2312 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2314 allowauth_func_size
= 8;
2315 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2318 allowauth_func_list
[allowauth_func_used
++] = func
;
2321 static NICKSERV_FUNC(cmd_allowauth
)
2323 struct userNode
*target
;
2324 struct handle_info
*hi
;
2327 NICKSERV_MIN_PARMS(2);
2328 if (!(target
= GetUserH(argv
[1]))) {
2329 reply("MSG_NICK_UNKNOWN", argv
[1]);
2332 if (target
->handle_info
) {
2333 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2336 if (IsStamped(target
)) {
2337 /* Unauthenticated users might still have been stamped
2338 previously and could therefore have a hidden host;
2339 do not allow them to authenticate to an account. */
2340 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2345 else if (!(hi
= get_handle_info(argv
[2]))) {
2346 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2350 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2351 reply("MSG_USER_OUTRANKED", hi
->handle
);
2354 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2355 || (hi
->opserv_level
> 0))
2356 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2357 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2360 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2361 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2362 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2363 if (nickserv_conf
.email_enabled
)
2364 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2366 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2367 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2369 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2371 for (n
=0; n
<allowauth_func_used
; n
++)
2372 allowauth_func_list
[n
](user
, target
, hi
);
2376 static NICKSERV_FUNC(cmd_authcookie
)
2378 struct handle_info
*hi
;
2380 NICKSERV_MIN_PARMS(2);
2381 if (user
->handle_info
) {
2382 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2385 if (IsStamped(user
)) {
2386 /* Unauthenticated users might still have been stamped
2387 previously and could therefore have a hidden host;
2388 do not allow them to authenticate to an account. */
2389 reply("NSMSG_STAMPED_AUTHCOOKIE");
2392 if (!(hi
= get_handle_info(argv
[1]))) {
2393 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2396 if (!hi
->email_addr
) {
2397 reply("MSG_SET_EMAIL_ADDR");
2400 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2404 static NICKSERV_FUNC(cmd_delcookie
)
2406 struct handle_info
*hi
;
2408 hi
= user
->handle_info
;
2410 reply("NSMSG_NO_COOKIE");
2413 switch (hi
->cookie
->type
) {
2416 reply("NSMSG_MUST_TIME_OUT");
2419 nickserv_eat_cookie(hi
->cookie
);
2420 reply("NSMSG_ATE_COOKIE");
2426 static NICKSERV_FUNC(cmd_odelcookie
)
2428 struct handle_info
*hi
;
2430 NICKSERV_MIN_PARMS(2);
2432 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2436 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2440 switch (hi
->cookie
->type
) {
2442 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2443 if (nickserv_conf
.sync_log
)
2444 SyncLog("ACCOUNTACC %s", hi
->handle
);
2446 case PASSWORD_CHANGE
:
2447 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2448 if (nickserv_conf
.sync_log
)
2449 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2452 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2453 if (nickserv_conf
.sync_log
)
2454 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2457 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2459 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2460 /* Falied to update email in ldap, but still
2461 * updated it here.. what should we do? */
2462 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2464 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2468 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2471 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2473 if (nickserv_conf
.sync_log
)
2474 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2477 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2478 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2482 nickserv_eat_cookie(hi
->cookie
);
2483 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2488 static NICKSERV_FUNC(cmd_resetpass
)
2490 struct handle_info
*hi
;
2491 char crypted
[MD5_CRYPT_LENGTH
];
2494 NICKSERV_MIN_PARMS(3);
2495 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2499 if (user
->handle_info
) {
2500 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2503 if (IsStamped(user
)) {
2504 /* Unauthenticated users might still have been stamped
2505 previously and could therefore have a hidden host;
2506 do not allow them to activate an account. */
2507 reply("NSMSG_STAMPED_RESETPASS");
2510 if (!(hi
= get_handle_info(argv
[1]))) {
2511 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2514 if (!hi
->email_addr
) {
2515 reply("MSG_SET_EMAIL_ADDR");
2518 cryptpass(argv
[2], crypted
);
2520 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2524 static NICKSERV_FUNC(cmd_cookie
)
2526 struct handle_info
*hi
;
2529 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2532 NICKSERV_MIN_PARMS(3);
2533 if (!(hi
= get_handle_info(argv
[1]))) {
2534 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2540 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2541 reply("NSMSG_HANDLE_SUSPENDED");
2546 reply("NSMSG_NO_COOKIE");
2550 /* Check validity of operation before comparing cookie to
2551 * prohibit guessing by authed users. */
2552 if (user
->handle_info
2553 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2554 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2555 reply("NSMSG_CANNOT_COOKIE");
2559 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2560 reply("NSMSG_BAD_COOKIE");
2564 switch (hi
->cookie
->type
) {
2567 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2569 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2570 /* Falied to update email in ldap, but still
2571 * updated it here.. what should we do? */
2572 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2577 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2578 set_user_handle_info(user
, hi
, 1);
2579 reply("NSMSG_HANDLE_ACTIVATED");
2580 if (nickserv_conf
.sync_log
)
2581 SyncLog("ACCOUNTACC %s", hi
->handle
);
2583 case PASSWORD_CHANGE
:
2585 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2587 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2588 /* Falied to update email in ldap, but still
2589 * updated it here.. what should we do? */
2590 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2595 set_user_handle_info(user
, hi
, 1);
2596 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2597 reply("NSMSG_PASSWORD_CHANGED");
2598 if (nickserv_conf
.sync_log
)
2599 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2603 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2605 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2606 /* Falied to update email in ldap, but still
2607 * updated it here.. what should we do? */
2608 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2613 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2615 * This should only happen if an OREGISTER was sent. Require
2616 * email must be enabled! - SiRVulcaN
2618 if (nickserv_conf
.sync_log
)
2619 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2622 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2623 reply("NSMSG_EMAIL_CHANGED");
2624 if (nickserv_conf
.sync_log
)
2625 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2628 set_user_handle_info(user
, hi
, 1);
2629 reply("NSMSG_AUTH_SUCCESS");
2632 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2633 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2637 nickserv_eat_cookie(hi
->cookie
);
2639 process_adduser_pending(user
);
2644 static NICKSERV_FUNC(cmd_oregnick
) {
2646 struct handle_info
*target
;
2647 struct nick_info
*ni
;
2649 NICKSERV_MIN_PARMS(3);
2650 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2653 if (!is_registerable_nick(nick
)) {
2654 reply("NSMSG_BAD_NICK", nick
);
2657 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2659 reply("NSMSG_NICK_EXISTS", nick
);
2662 register_nick(nick
, target
);
2663 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2667 static NICKSERV_FUNC(cmd_regnick
) {
2669 struct nick_info
*ni
;
2671 if (!is_registerable_nick(user
->nick
)) {
2672 reply("NSMSG_BAD_NICK", user
->nick
);
2675 /* count their nicks, see if it's too many */
2676 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2677 if (n
>= nickserv_conf
.nicks_per_handle
) {
2678 reply("NSMSG_TOO_MANY_NICKS");
2681 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2683 reply("NSMSG_NICK_EXISTS", user
->nick
);
2686 register_nick(user
->nick
, user
->handle_info
);
2687 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2691 static NICKSERV_FUNC(cmd_pass
)
2693 struct handle_info
*hi
;
2694 char *old_pass
, *new_pass
;
2695 char crypted
[MD5_CRYPT_LENGTH
+1];
2700 NICKSERV_MIN_PARMS(3);
2701 hi
= user
->handle_info
;
2705 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2708 if(nickserv_conf
.ldap_enable
) {
2709 ldap_result
= ldap_check_auth(hi
->handle
, old_pass
);
2710 if(ldap_result
!= LDAP_SUCCESS
) {
2711 if(ldap_result
== LDAP_INVALID_CREDENTIALS
)
2712 reply("NSMSG_PASSWORD_INVALID");
2714 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2719 if (!checkpass(old_pass
, hi
->passwd
)) {
2720 argv
[1] = "BADPASS";
2721 reply("NSMSG_PASSWORD_INVALID");
2724 cryptpass(new_pass
, crypted
);
2726 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2728 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
2729 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2734 //cryptpass(new_pass, hi->passwd);
2735 strcpy(hi
->passwd
, crypted
);
2736 if (nickserv_conf
.sync_log
)
2737 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2739 reply("NSMSG_PASS_SUCCESS");
2744 nickserv_addmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2747 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2748 for (i
=0; i
<hi
->masks
->used
; i
++) {
2749 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2750 reply("NSMSG_ADDMASK_ALREADY", new_mask
);
2755 string_list_append(hi
->masks
, new_mask
);
2756 reply("NSMSG_ADDMASK_SUCCESS", new_mask
);
2760 static NICKSERV_FUNC(cmd_addmask
)
2763 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2764 int res
= nickserv_addmask(cmd
, user
, user
->handle_info
, mask
);
2768 if (!is_gline(argv
[1])) {
2769 reply("NSMSG_MASK_INVALID", argv
[1]);
2772 return nickserv_addmask(cmd
, user
, user
->handle_info
, argv
[1]);
2776 static NICKSERV_FUNC(cmd_oaddmask
)
2778 struct handle_info
*hi
;
2780 NICKSERV_MIN_PARMS(3);
2781 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2783 return nickserv_addmask(cmd
, user
, hi
, argv
[2]);
2787 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2790 for (i
=0; i
<hi
->masks
->used
; i
++) {
2791 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2792 char *old_mask
= hi
->masks
->list
[i
];
2793 if (hi
->masks
->used
== 1) {
2794 reply("NSMSG_DELMASK_NOTLAST");
2797 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2798 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2803 reply("NSMSG_DELMASK_NOT_FOUND");
2807 static NICKSERV_FUNC(cmd_delmask
)
2809 NICKSERV_MIN_PARMS(2);
2810 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1]);
2813 static NICKSERV_FUNC(cmd_odelmask
)
2815 struct handle_info
*hi
;
2816 NICKSERV_MIN_PARMS(3);
2817 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2819 return nickserv_delmask(cmd
, user
, hi
, argv
[2]);
2823 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2824 unsigned int nn
, add
= 1, pos
;
2825 unsigned long added
, removed
, flag
;
2827 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2829 case '+': add
= 1; break;
2830 case '-': add
= 0; break;
2832 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2833 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2836 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2837 /* cheesy avoidance of looking up the flag name.. */
2838 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2841 flag
= 1 << (pos
- 1);
2843 added
|= flag
, removed
&= ~flag
;
2845 removed
|= flag
, added
&= ~flag
;
2850 *premoved
= removed
;
2855 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2857 unsigned long before
, after
, added
, removed
;
2858 struct userNode
*uNode
;
2860 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2861 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2863 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2864 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2866 /* Strip helping flag if they're only a support helper and not
2867 * currently in #support. */
2868 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2869 struct channelList
*schannels
;
2871 schannels
= chanserv_support_channels();
2872 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2873 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2874 if (GetUserMode(schannels
->list
[ii
], uNode
))
2876 if (ii
< schannels
->used
)
2880 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2883 if (after
&& !before
) {
2884 /* Add user to current helper list. */
2885 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2886 userList_append(&curr_helpers
, uNode
);
2887 } else if (!after
&& before
) {
2888 /* Remove user from current helper list. */
2889 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2890 userList_remove(&curr_helpers
, uNode
);
2897 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2901 char *set_display
[] = {
2902 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2903 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2904 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2907 reply("NSMSG_SETTING_LIST");
2908 reply("NSMSG_SETTING_LIST_HEADER");
2910 /* Do this so options are presented in a consistent order. */
2911 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2912 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2913 opt(cmd
, user
, hi
, override
, 0, NULL
);
2914 reply("NSMSG_SETTING_LIST_END");
2917 static NICKSERV_FUNC(cmd_set
)
2919 struct handle_info
*hi
;
2922 hi
= user
->handle_info
;
2924 set_list(cmd
, user
, hi
, 0);
2927 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2928 reply("NSMSG_INVALID_OPTION", argv
[1]);
2931 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2934 static NICKSERV_FUNC(cmd_oset
)
2936 struct handle_info
*hi
;
2939 NICKSERV_MIN_PARMS(2);
2941 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2945 set_list(cmd
, user
, hi
, 0);
2949 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2950 reply("NSMSG_INVALID_OPTION", argv
[2]);
2954 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
2957 static OPTION_FUNC(opt_info
)
2961 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2963 hi
->infoline
= NULL
;
2965 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2969 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2970 reply("NSMSG_SET_INFO", info
);
2974 static OPTION_FUNC(opt_width
)
2977 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2979 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2980 hi
->screen_width
= MIN_LINE_SIZE
;
2981 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2982 hi
->screen_width
= MAX_LINE_SIZE
;
2984 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
2988 static OPTION_FUNC(opt_tablewidth
)
2991 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2993 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2994 hi
->table_width
= MIN_LINE_SIZE
;
2995 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2996 hi
->table_width
= MAX_LINE_SIZE
;
2998 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
3002 static OPTION_FUNC(opt_color
)
3005 if (enabled_string(argv
[1]))
3006 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
3007 else if (disabled_string(argv
[1]))
3008 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
3010 reply("MSG_INVALID_BINARY", argv
[1]);
3015 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
3019 static OPTION_FUNC(opt_privmsg
)
3022 if (enabled_string(argv
[1]))
3023 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
3024 else if (disabled_string(argv
[1]))
3025 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
3027 reply("MSG_INVALID_BINARY", argv
[1]);
3032 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
3036 static OPTION_FUNC(opt_autohide
)
3039 if (enabled_string(argv
[1]))
3040 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
3041 else if (disabled_string(argv
[1]))
3042 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
3044 reply("MSG_INVALID_BINARY", argv
[1]);
3049 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
3053 static OPTION_FUNC(opt_style
)
3058 if (!irccasecmp(argv
[1], "Clean"))
3059 hi
->userlist_style
= HI_STYLE_CLEAN
;
3060 else if (!irccasecmp(argv
[1], "Advanced"))
3061 hi
->userlist_style
= HI_STYLE_ADVANCED
;
3062 else if (!irccasecmp(argv
[1], "Classic"))
3063 hi
->userlist_style
= HI_STYLE_CLASSIC
;
3064 else /* Default to normal */
3065 hi
->userlist_style
= HI_STYLE_NORMAL
;
3066 } /* TODO: give error if unknow style is chosen */
3068 switch (hi
->userlist_style
) {
3069 case HI_STYLE_ADVANCED
:
3072 case HI_STYLE_CLASSIC
:
3075 case HI_STYLE_CLEAN
:
3078 case HI_STYLE_NORMAL
:
3083 reply("NSMSG_SET_STYLE", style
);
3087 static OPTION_FUNC(opt_announcements
)
3092 if (enabled_string(argv
[1]))
3093 hi
->announcements
= 'y';
3094 else if (disabled_string(argv
[1]))
3095 hi
->announcements
= 'n';
3096 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
3097 hi
->announcements
= '?';
3099 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
3104 switch (hi
->announcements
) {
3105 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
3106 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
3107 case '?': choice
= "default"; break;
3108 default: choice
= "unknown"; break;
3110 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
3114 static OPTION_FUNC(opt_password
)
3116 char crypted
[MD5_CRYPT_LENGTH
+1];
3121 reply("NSMSG_USE_CMD_PASS");
3125 cryptpass(argv
[1], crypted
);
3127 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3129 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
3130 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3135 strcpy(hi
->passwd
, crypted
);
3136 if (nickserv_conf
.sync_log
)
3137 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
3139 reply("NSMSG_SET_PASSWORD", "***");
3143 static OPTION_FUNC(opt_flags
)
3146 unsigned int ii
, flen
;
3149 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3154 nickserv_apply_flags(user
, hi
, argv
[1]);
3156 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
3157 if (hi
->flags
& (1 << ii
))
3158 flags
[flen
++] = handle_flags
[ii
];
3161 reply("NSMSG_SET_FLAGS", flags
);
3163 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
3167 static OPTION_FUNC(opt_email
)
3171 if (!valid_email(argv
[1])) {
3172 reply("NSMSG_BAD_EMAIL_ADDR");
3175 if ((str
= sendmail_prohibited_address(argv
[1]))) {
3176 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
3179 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
3180 reply("NSMSG_EMAIL_SAME");
3182 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
3185 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3187 if((rc
= ldap_do_modify(hi
->handle
, NULL
, argv
[1])) != LDAP_SUCCESS
) {
3188 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3193 nickserv_set_email_addr(hi
, argv
[1]);
3195 nickserv_eat_cookie(hi
->cookie
);
3196 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3199 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3203 static OPTION_FUNC(opt_maxlogins
)
3205 unsigned char maxlogins
;
3207 maxlogins
= strtoul(argv
[1], NULL
, 0);
3208 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
3209 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
3212 hi
->maxlogins
= maxlogins
;
3214 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
3215 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
3219 static OPTION_FUNC(opt_advanced
)
3222 if (enabled_string(argv
[1]))
3223 HANDLE_SET_FLAG(hi
, ADVANCED
);
3224 else if (disabled_string(argv
[1]))
3225 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
3227 reply("MSG_INVALID_BINARY", argv
[1]);
3232 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
3236 static OPTION_FUNC(opt_language
)
3238 struct language
*lang
;
3240 lang
= language_find(argv
[1]);
3241 if (irccasecmp(lang
->name
, argv
[1]))
3242 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
3243 hi
->language
= lang
;
3245 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
3249 /* Called from opserv from cmd_access */
3251 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
3252 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
3254 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
3255 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
3256 && (user
->handle_info
->opserv_level
< 1000))) {
3257 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
3260 if ((user
->handle_info
->opserv_level
< new_level
)
3261 || ((user
->handle_info
->opserv_level
== new_level
)
3262 && (user
->handle_info
->opserv_level
< 1000))) {
3263 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
3266 if (user
->handle_info
== target
) {
3267 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
3271 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_oper_group_dn
) && *(nickserv_conf
.ldap_admin_dn
)) {
3273 if(new_level
> nickserv_conf
.ldap_oper_group_level
)
3274 rc
= ldap_add2group(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3276 rc
= ldap_delfromgroup(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3277 if(rc
!= LDAP_SUCCESS
&& rc
!= LDAP_TYPE_OR_VALUE_EXISTS
&& rc
!= LDAP_NO_SUCH_ATTRIBUTE
) {
3278 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3283 if (target
->opserv_level
== new_level
)
3285 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
3286 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
3287 target
->opserv_level
= new_level
;
3291 static OPTION_FUNC(opt_level
)
3296 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3300 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
3301 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
3305 static OPTION_FUNC(opt_epithet
)
3307 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
3309 struct userNode
*target
, *next_un
;
3312 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3316 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
3320 if ((epithet
[0] == '*') && !epithet
[1])
3323 hi
->epithet
= strdup(epithet
);
3325 for (target
= hi
->users
; target
; target
= next_un
) {
3326 irc_swhois(nickserv
, target
, hi
->epithet
);
3328 next_un
= target
->next_authed
;
3333 reply("NSMSG_SET_EPITHET", hi
->epithet
);
3335 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
3339 static OPTION_FUNC(opt_title
)
3345 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
3347 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3352 if(!strcmp(title
, "*")) {
3354 hi
->fakehost
= NULL
;
3357 if (strchr(title
, '.')) {
3358 reply("NSMSG_TITLE_INVALID");
3361 /* Alphanumeric titles only. */
3362 for(sptr
= title
; *sptr
; sptr
++) {
3363 if(!isalnum(*sptr
) && *sptr
!= '-') {
3364 reply("NSMSG_TITLE_INVALID");
3368 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
3369 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3370 reply("NSMSG_TITLE_TRUNCATED");
3374 hi
->fakehost
= malloc(strlen(title
)+2);
3375 hi
->fakehost
[0] = '.';
3376 strcpy(hi
->fakehost
+1, title
);
3379 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3380 title
= hi
->fakehost
+ 1;
3382 /* If theres no title set then the default title will therefore
3383 be the first part of hidden_host in x3.conf, so for
3384 consistency with opt_fakehost we will print this here.
3385 This isnt actually used in P10, its just handled to keep from crashing... */
3386 char *hs
, *hidden_suffix
, *rest
;
3388 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3389 hidden_suffix
= strdup(hs
);
3391 /* Yes we do this twice */
3392 if((rest
= strchr(hidden_suffix
, '.')))
3395 title
= hidden_suffix
;
3399 /* A lame default if someone configured hidden_host to something lame */
3400 title
= strdup("users");
3401 free(hidden_suffix
);
3407 none
= user_find_message(user
, "MSG_NONE");
3408 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3413 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3417 // check for a dot in the vhost
3418 if(strchr(vhost
, '.') == NULL
) {
3419 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3423 // check for a @ in the vhost
3424 if(strchr(vhost
, '@') != NULL
) {
3425 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3429 // check for denied words, inspired by monk at paki.sex
3430 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3431 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3432 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3437 // check for ircu's HOSTLEN length.
3438 if(strlen(vhost
) >= HOSTLEN
) {
3439 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3443 /* This can be handled by the regex now if desired.
3444 if (vhost[strspn(vhost, "0123456789.")]) {
3445 hostname = vhost + strlen(vhost);
3446 for (depth = 1; depth && (hostname > vhost); depth--) {
3448 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3451 if (*hostname == '.') hostname++; * advance past last dot we saw *
3452 if(strlen(hostname) > 4) {
3453 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3458 /* test either regex or as valid handle */
3459 if (nickserv_conf
.valid_fakehost_regex_set
) {
3460 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3463 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3464 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3466 if(err
== REG_NOMATCH
) {
3467 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3476 static OPTION_FUNC(opt_fakehost
)
3480 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3482 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3487 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3488 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3491 if (!strcmp(fake
, "*")) {
3494 hi
->fakehost
= NULL
;
3497 else if (!check_vhost(argv
[1], user
, cmd
)) {
3498 /* check_vhost takes care of error reply */
3504 hi
->fakehost
= strdup(fake
);
3507 fake
= hi
->fakehost
;
3509 fake
= generate_fakehost(hi
);
3511 /* Tell them we set the host */
3513 fake
= user_find_message(user
, "MSG_NONE");
3514 reply("NSMSG_SET_FAKEHOST", fake
);
3518 static OPTION_FUNC(opt_note
)
3521 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3526 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3531 if ((text
[0] == '*') && !text
[1])
3534 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3539 reply("NSMSG_SET_NOTE", hi
->note
? hi
->note
->note
: user_find_message(user
, "MSG_NONE"));
3543 static NICKSERV_FUNC(cmd_reclaim
)
3545 struct handle_info
*hi
;
3546 struct nick_info
*ni
;
3547 struct userNode
*victim
;
3549 NICKSERV_MIN_PARMS(2);
3550 hi
= user
->handle_info
;
3551 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3553 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3556 if (ni
->owner
!= user
->handle_info
) {
3557 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3560 victim
= GetUserH(ni
->nick
);
3562 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3565 if (victim
== user
) {
3566 reply("NSMSG_NICK_USER_YOU");
3569 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3570 switch (nickserv_conf
.reclaim_action
) {
3571 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3572 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3573 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3574 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3579 static NICKSERV_FUNC(cmd_unregnick
)
3582 struct handle_info
*hi
;
3583 struct nick_info
*ni
;
3585 hi
= user
->handle_info
;
3586 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3587 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3589 reply("NSMSG_UNKNOWN_NICK", nick
);
3592 if (hi
!= ni
->owner
) {
3593 reply("NSMSG_NOT_YOUR_NICK", nick
);
3596 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3601 static NICKSERV_FUNC(cmd_ounregnick
)
3603 struct nick_info
*ni
;
3605 NICKSERV_MIN_PARMS(2);
3606 if (!(ni
= get_nick_info(argv
[1]))) {
3607 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3610 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3611 reply("MSG_USER_OUTRANKED", ni
->nick
);
3614 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3619 static NICKSERV_FUNC(cmd_unregister
)
3621 struct handle_info
*hi
;
3624 NICKSERV_MIN_PARMS(2);
3625 hi
= user
->handle_info
;
3628 if (checkpass(passwd
, hi
->passwd
)) {
3629 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3634 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3635 reply("NSMSG_PASSWORD_INVALID");
3640 static NICKSERV_FUNC(cmd_ounregister
)
3642 struct handle_info
*hi
;
3644 NICKSERV_MIN_PARMS(2);
3645 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
3647 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3653 static NICKSERV_FUNC(cmd_status
)
3655 if (nickserv_conf
.disable_nicks
) {
3656 reply("NSMSG_GLOBAL_STATS_NONICK",
3657 dict_size(nickserv_handle_dict
));
3659 if (user
->handle_info
) {
3661 struct nick_info
*ni
;
3662 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3663 reply("NSMSG_HANDLE_STATS", cnt
);
3665 reply("NSMSG_HANDLE_NONE");
3667 reply("NSMSG_GLOBAL_STATS",
3668 dict_size(nickserv_handle_dict
),
3669 dict_size(nickserv_nick_dict
));
3674 static NICKSERV_FUNC(cmd_ghost
)
3676 struct userNode
*target
;
3677 char reason
[MAXLEN
];
3679 NICKSERV_MIN_PARMS(2);
3680 if (!(target
= GetUserH(argv
[1]))) {
3681 reply("MSG_NICK_UNKNOWN", argv
[1]);
3684 if (target
== user
) {
3685 reply("NSMSG_CANNOT_GHOST_SELF");
3688 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3689 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3692 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3693 DelUser(target
, nickserv
, 1, reason
);
3694 reply("NSMSG_GHOST_KILLED", argv
[1]);
3698 static NICKSERV_FUNC(cmd_vacation
)
3700 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3701 reply("NSMSG_ON_VACATION");
3706 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3708 struct handle_info
*hi
;
3711 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3713 saxdb_start_record(ctx
, iter_key(it
), 0);
3714 if (hi
->announcements
!= '?') {
3715 flags
[0] = hi
->announcements
;
3717 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3720 struct handle_cookie
*cookie
= hi
->cookie
;
3723 switch (cookie
->type
) {
3724 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3725 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3726 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3727 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3728 default: type
= NULL
; break;
3731 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3732 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3733 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3735 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3736 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3737 saxdb_end_record(ctx
);
3741 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3743 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3745 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3746 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3747 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3748 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3749 saxdb_end_record(ctx
);
3753 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3757 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3758 if (hi
->flags
& (1 << ii
))
3759 flags
[flen
++] = handle_flags
[ii
];
3761 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3764 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3765 if (hi
->last_quit_host
[0])
3766 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3767 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3768 if (hi
->masks
->used
)
3769 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3770 if (hi
->ignores
->used
)
3771 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3773 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3775 struct string_list
*slist
;
3776 struct nick_info
*ni
;
3778 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3779 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3780 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3784 if (hi
->opserv_level
)
3785 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3786 if (hi
->language
!= lang_C
)
3787 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3788 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3789 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3790 if (hi
->screen_width
)
3791 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3792 if (hi
->table_width
)
3793 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3794 flags
[0] = hi
->userlist_style
;
3796 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3797 saxdb_end_record(ctx
);
3803 static handle_merge_func_t
*handle_merge_func_list
;
3804 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3807 reg_handle_merge_func(handle_merge_func_t func
)
3809 if (handle_merge_func_used
== handle_merge_func_size
) {
3810 if (handle_merge_func_size
) {
3811 handle_merge_func_size
<<= 1;
3812 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3814 handle_merge_func_size
= 8;
3815 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3818 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3821 static NICKSERV_FUNC(cmd_merge
)
3823 struct handle_info
*hi_from
, *hi_to
;
3824 struct userNode
*last_user
;
3825 struct userData
*cList
, *cListNext
;
3826 unsigned int ii
, jj
, n
;
3828 NICKSERV_MIN_PARMS(3);
3830 if (!(hi_from
= get_victim_oper(cmd
, user
, argv
[1])))
3832 if (!(hi_to
= get_victim_oper(cmd
, user
, argv
[2])))
3834 if (hi_to
== hi_from
) {
3835 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3839 for (n
=0; n
<handle_merge_func_used
; n
++)
3840 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3842 /* Append "from" handle's nicks to "to" handle's nick list. */
3844 struct nick_info
*last_ni
;
3845 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3846 last_ni
->next
= hi_from
->nicks
;
3848 while (hi_from
->nicks
) {
3849 hi_from
->nicks
->owner
= hi_to
;
3850 hi_from
->nicks
= hi_from
->nicks
->next
;
3853 /* Merge the hostmasks. */
3854 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3855 char *mask
= hi_from
->masks
->list
[ii
];
3856 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3857 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3859 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3860 string_list_append(hi_to
->masks
, strdup(mask
));
3863 /* Merge the ignores. */
3864 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3865 char *ignore
= hi_from
->ignores
->list
[ii
];
3866 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3867 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3869 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3870 string_list_append(hi_to
->ignores
, strdup(ignore
));
3873 /* Merge the lists of authed users. */
3875 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3876 last_user
->next_authed
= hi_from
->users
;
3878 hi_to
->users
= hi_from
->users
;
3880 /* Repoint the old "from" handle's users. */
3881 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3882 last_user
->handle_info
= hi_to
;
3884 hi_from
->users
= NULL
;
3886 /* Merge channel userlists. */
3887 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3888 struct userData
*cList2
;
3889 cListNext
= cList
->u_next
;
3890 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3891 if (cList
->channel
== cList2
->channel
)
3893 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3894 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
);
3895 /* keep cList2 in hi_to; remove cList from hi_from */
3896 del_channel_user(cList
, 1);
3899 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
);
3900 /* remove the lower-ranking cList2 from hi_to */
3901 del_channel_user(cList2
, 1);
3903 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3905 /* cList needs to be moved from hi_from to hi_to */
3906 cList
->handle
= hi_to
;
3907 /* Remove from linked list for hi_from */
3908 assert(!cList
->u_prev
);
3909 hi_from
->channels
= cList
->u_next
;
3911 cList
->u_next
->u_prev
= cList
->u_prev
;
3912 /* Add to linked list for hi_to */
3913 cList
->u_prev
= NULL
;
3914 cList
->u_next
= hi_to
->channels
;
3915 if (hi_to
->channels
)
3916 hi_to
->channels
->u_prev
= cList
;
3917 hi_to
->channels
= cList
;
3921 /* Do they get an OpServ level promotion? */
3922 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3923 hi_to
->opserv_level
= hi_from
->opserv_level
;
3925 /* What about last seen time? */
3926 if (hi_from
->lastseen
> hi_to
->lastseen
)
3927 hi_to
->lastseen
= hi_from
->lastseen
;
3929 /* Does a fakehost carry over? (This intentionally doesn't set it
3930 * for users previously attached to hi_to. They'll just have to
3933 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3934 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3936 /* Notify of success. */
3937 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3938 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
3939 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3941 /* Unregister the "from" handle. */
3942 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3943 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
3944 * the process isn't completed.
3950 struct nickserv_discrim
{
3951 unsigned int limit
, min_level
, max_level
;
3952 unsigned long flags_on
, flags_off
;
3953 time_t min_registered
, max_registered
;
3955 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3956 const char *nickmask
;
3957 const char *hostmask
;
3958 const char *handlemask
;
3959 const char *emailmask
;
3961 unsigned int inldap
;
3965 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3967 struct discrim_apply_info
{
3968 struct nickserv_discrim
*discrim
;
3969 discrim_search_func func
;
3970 struct userNode
*source
;
3971 unsigned int matched
;
3974 static struct nickserv_discrim
*
3975 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
3978 struct nickserv_discrim
*discrim
;
3980 discrim
= malloc(sizeof(*discrim
));
3981 memset(discrim
, 0, sizeof(*discrim
));
3982 discrim
->min_level
= 0;
3983 discrim
->max_level
= ~0;
3984 discrim
->limit
= 50;
3985 discrim
->min_registered
= 0;
3986 discrim
->max_registered
= INT_MAX
;
3987 discrim
->lastseen
= now
;
3989 discrim
->inldap
= 2;
3992 for (i
=0; i
<argc
; i
++) {
3993 if (i
== argc
- 1) {
3994 reply("MSG_MISSING_PARAMS", argv
[i
]);
3997 if (!irccasecmp(argv
[i
], "limit")) {
3998 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3999 } else if (!irccasecmp(argv
[i
], "flags")) {
4000 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
4001 } else if (!irccasecmp(argv
[i
], "registered")) {
4002 const char *cmp
= argv
[++i
];
4003 if (cmp
[0] == '<') {
4004 if (cmp
[1] == '=') {
4005 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
4007 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
4009 } else if (cmp
[0] == '=') {
4010 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
4011 } else if (cmp
[0] == '>') {
4012 if (cmp
[1] == '=') {
4013 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
4015 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
4018 reply("MSG_INVALID_CRITERIA", cmp
);
4020 } else if (!irccasecmp(argv
[i
], "seen")) {
4021 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
4022 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
4023 discrim
->nickmask
= argv
[++i
];
4024 } else if (!irccasecmp(argv
[i
], "hostmask")) {
4026 if (!irccasecmp(argv
[i
], "exact")) {
4027 if (i
== argc
- 1) {
4028 reply("MSG_MISSING_PARAMS", argv
[i
]);
4031 discrim
->hostmask_type
= EXACT
;
4032 } else if (!irccasecmp(argv
[i
], "subset")) {
4033 if (i
== argc
- 1) {
4034 reply("MSG_MISSING_PARAMS", argv
[i
]);
4037 discrim
->hostmask_type
= SUBSET
;
4038 } else if (!irccasecmp(argv
[i
], "superset")) {
4039 if (i
== argc
- 1) {
4040 reply("MSG_MISSING_PARAMS", argv
[i
]);
4043 discrim
->hostmask_type
= SUPERSET
;
4044 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
4045 if (i
== argc
- 1) {
4046 reply("MSG_MISSING_PARAMS", argv
[i
]);
4049 discrim
->hostmask_type
= LASTQUIT
;
4052 discrim
->hostmask_type
= SUPERSET
;
4054 discrim
->hostmask
= argv
[++i
];
4055 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask") || !irccasecmp(argv
[i
], "account")) {
4056 if (!irccasecmp(argv
[++i
], "*")) {
4057 discrim
->handlemask
= 0;
4059 discrim
->handlemask
= argv
[i
];
4061 } else if (!irccasecmp(argv
[i
], "email")) {
4062 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
4063 reply("MSG_NO_SEARCH_ACCESS", "email");
4065 } else if (!irccasecmp(argv
[++i
], "*")) {
4066 discrim
->emailmask
= 0;
4068 discrim
->emailmask
= argv
[i
];
4070 } else if (!irccasecmp(argv
[i
], "access")) {
4071 const char *cmp
= argv
[++i
];
4072 if (cmp
[0] == '<') {
4073 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
4074 if (cmp
[1] == '=') {
4075 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
4077 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
4079 } else if (cmp
[0] == '=') {
4080 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
4081 } else if (cmp
[0] == '>') {
4082 if (cmp
[1] == '=') {
4083 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
4085 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
4088 reply("MSG_INVALID_CRITERIA", cmp
);
4091 } else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[i
], "inldap")) {
4093 if(true_string(argv
[i
])) {
4094 discrim
->inldap
= 1;
4096 else if (false_string(argv
[i
])) {
4097 discrim
->inldap
= 0;
4100 reply("MSG_INVALID_BINARY", argv
[i
]);
4104 reply("MSG_INVALID_CRITERIA", argv
[i
]);
4115 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
4117 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
4118 || (discrim
->flags_off
& hi
->flags
)
4119 || (discrim
->min_registered
> hi
->registered
)
4120 || (discrim
->max_registered
< hi
->registered
)
4121 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
4122 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
4123 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
4124 || (discrim
->min_level
> hi
->opserv_level
)
4125 || (discrim
->max_level
< hi
->opserv_level
)) {
4128 if (discrim
->hostmask
) {
4130 for (i
=0; i
<hi
->masks
->used
; i
++) {
4131 const char *mask
= hi
->masks
->list
[i
];
4132 if ((discrim
->hostmask_type
== SUBSET
)
4133 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
4134 else if ((discrim
->hostmask_type
== EXACT
)
4135 && !irccasecmp(discrim
->hostmask
, mask
)) break;
4136 else if ((discrim
->hostmask_type
== SUPERSET
)
4137 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
4138 else if ((discrim
->hostmask_type
== LASTQUIT
)
4139 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
4141 if (i
==hi
->masks
->used
) return 0;
4143 if (discrim
->nickmask
) {
4144 struct nick_info
*nick
= hi
->nicks
;
4146 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
4149 if (!nick
) return 0;
4152 if(nickserv_conf
.ldap_enable
&& discrim
->inldap
!= 2) {
4154 rc
= ldap_get_user_info(hi
->handle
, NULL
);
4155 if(discrim
->inldap
== 1 && rc
!= LDAP_SUCCESS
)
4157 if(discrim
->inldap
== 0 && rc
== LDAP_SUCCESS
)
4166 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
4168 dict_iterator_t it
, next
;
4169 unsigned int matched
;
4171 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
4172 it
&& (matched
< discrim
->limit
);
4174 next
= iter_next(it
);
4175 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
4176 dsf(source
, iter_data(it
));
4184 search_print_func(struct userNode
*source
, struct handle_info
*match
)
4186 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
4190 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
4195 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
4197 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
4198 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
4203 search_add2ldap_func (struct userNode
*source
, struct handle_info
*match
)
4206 if(match
->email_addr
&& match
->passwd
&& match
->handle
) {
4207 rc
= ldap_do_add(match
->handle
, match
->passwd
, match
->email_addr
);
4208 if(rc
!= LDAP_SUCCESS
) {
4209 send_message(source
, nickserv
, "NSMSG_LDAP_FAIL_ADD", match
->handle
, ldap_err2string(rc
));
4216 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
4218 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
4219 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
4220 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
4221 return hi_b
->opserv_level
- hi_a
->opserv_level
;
4222 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
4226 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
4228 struct handle_info_list hil
;
4229 struct helpfile_table tbl
;
4234 memset(&hil
, 0, sizeof(hil
));
4235 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
4236 struct handle_info
*hi
= iter_data(it
);
4237 if (hi
->opserv_level
)
4238 handle_info_list_append(&hil
, hi
);
4240 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
4241 tbl
.length
= hil
.used
+ 1;
4243 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
4244 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
4245 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4248 for (ii
= 0; ii
< hil
.used
; ) {
4249 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4250 ary
[0] = hil
.list
[ii
]->handle
;
4251 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
4252 tbl
.contents
[++ii
] = ary
;
4254 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4255 /*reply("MSG_MATCH_COUNT", hil.used); */
4256 for (ii
= 0; ii
< hil
.used
; ii
++)
4257 free(tbl
.contents
[ii
]);
4262 static NICKSERV_FUNC(cmd_search
)
4264 struct nickserv_discrim
*discrim
;
4265 discrim_search_func action
;
4266 struct svccmd
*subcmd
;
4267 unsigned int matches
;
4270 NICKSERV_MIN_PARMS(3);
4271 sprintf(buf
, "search %s", argv
[1]);
4272 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
4273 if (!irccasecmp(argv
[1], "print"))
4274 action
= search_print_func
;
4275 else if (!irccasecmp(argv
[1], "count"))
4276 action
= search_count_func
;
4277 else if (!irccasecmp(argv
[1], "unregister"))
4278 action
= search_unregister_func
;
4280 else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[1], "add2ldap"))
4281 action
= search_add2ldap_func
;
4284 reply("NSMSG_INVALID_ACTION", argv
[1]);
4288 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
4291 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
4295 if (action
== search_print_func
)
4296 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4297 else if (action
== search_count_func
)
4298 discrim
->limit
= INT_MAX
;
4300 matches
= nickserv_discrim_search(discrim
, action
, user
);
4303 reply("MSG_MATCH_COUNT", matches
);
4305 reply("MSG_NO_MATCHES");
4311 static MODCMD_FUNC(cmd_checkpass
)
4313 struct handle_info
*hi
;
4315 NICKSERV_MIN_PARMS(3);
4316 if (!(hi
= get_handle_info(argv
[1]))) {
4317 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
4320 if (checkpass(argv
[2], hi
->passwd
))
4321 reply("CHECKPASS_YES");
4323 reply("CHECKPASS_NO");
4329 nickserv_db_read_handle(char *handle
, dict_t obj
)
4332 struct string_list
*masks
, *slist
, *ignores
;
4333 struct handle_info
*hi
;
4334 struct userNode
*authed_users
;
4335 struct userData
*channels
;
4336 unsigned long int id
;
4339 char *setter
, *note
;
4342 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
4343 id
= str
? strtoul(str
, NULL
, 0) : 0;
4344 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
4346 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
4349 if ((hi
= get_handle_info(handle
))) {
4350 authed_users
= hi
->users
;
4351 channels
= hi
->channels
;
4353 hi
->channels
= NULL
;
4354 dict_remove(nickserv_handle_dict
, hi
->handle
);
4356 authed_users
= NULL
;
4359 if(nickserv_conf
.force_handles_lowercase
)
4360 irc_strtolower(handle
);
4361 hi
= register_handle(handle
, str
, id
);
4363 hi
->users
= authed_users
;
4364 while (authed_users
) {
4365 authed_users
->handle_info
= hi
;
4366 authed_users
= authed_users
->next_authed
;
4369 hi
->channels
= channels
;
4370 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
4371 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
4372 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
4373 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
4374 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
4375 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
4376 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
4377 hi
->language
= language_find(str
? str
: "C");
4378 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
4379 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
4380 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
4382 hi
->infoline
= strdup(str
);
4383 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
4384 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4385 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
4386 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
4387 /* We want to read the nicks even if disable_nicks is set. This is so
4388 * that we don't lose the nick data entirely. */
4389 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
4391 for (ii
=0; ii
<slist
->used
; ii
++)
4392 register_nick(slist
->list
[ii
], hi
);
4394 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
4396 for (ii
=0; str
[ii
]; ii
++)
4397 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
4399 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
4400 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4401 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
4402 hi
->announcements
= str
? str
[0] : '?';
4403 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
4404 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
4405 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
4406 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
4407 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
4409 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
4411 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
4412 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
4414 nickserv_set_email_addr(hi
, str
);
4415 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
4417 hi
->epithet
= strdup(str
);
4418 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
4420 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
4421 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
4422 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4423 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
4424 if (setter
&& date
&& note
)
4426 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
4431 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
4433 hi
->fakehost
= strdup(str
);
4435 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4437 const char *data
, *type
, *expires
, *cookie_str
;
4438 struct handle_cookie
*cookie
;
4440 cookie
= calloc(1, sizeof(*cookie
));
4441 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4442 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4443 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4444 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4445 if (!type
|| !expires
|| !cookie_str
) {
4446 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4449 if (!irccasecmp(type
, KEY_ACTIVATION
))
4450 cookie
->type
= ACTIVATION
;
4451 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4452 cookie
->type
= PASSWORD_CHANGE
;
4453 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4454 cookie
->type
= EMAIL_CHANGE
;
4455 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4456 cookie
->type
= ALLOWAUTH
;
4458 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4461 cookie
->expires
= strtoul(expires
, NULL
, 0);
4462 if (cookie
->expires
< now
)
4465 cookie
->data
= strdup(data
);
4466 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4470 nickserv_bake_cookie(cookie
);
4472 nickserv_free_cookie(cookie
);
4477 nickserv_saxdb_read(dict_t db
) {
4479 struct record_data
*rd
;
4482 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4484 handle
= strdup(iter_key(it
));
4485 nickserv_db_read_handle(handle
, rd
->d
.object
);
4491 static NICKSERV_FUNC(cmd_mergedb
)
4493 struct timeval start
, stop
;
4496 NICKSERV_MIN_PARMS(2);
4497 gettimeofday(&start
, NULL
);
4498 if (!(db
= parse_database(argv
[1]))) {
4499 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4502 nickserv_saxdb_read(db
);
4504 gettimeofday(&stop
, NULL
);
4505 stop
.tv_sec
-= start
.tv_sec
;
4506 stop
.tv_usec
-= start
.tv_usec
;
4507 if (stop
.tv_usec
< 0) {
4509 stop
.tv_usec
+= 1000000;
4511 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4516 expire_handles(UNUSED_ARG(void *data
))
4518 dict_iterator_t it
, next
;
4520 struct handle_info
*hi
;
4522 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4523 next
= iter_next(it
);
4525 if ((hi
->opserv_level
> 0)
4527 || HANDLE_FLAGGED(hi
, FROZEN
)
4528 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4531 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4532 if ((now
- hi
->lastseen
) > expiry
) {
4533 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4534 nickserv_unregister_handle(hi
, NULL
, NULL
);
4538 if (nickserv_conf
.handle_expire_frequency
)
4539 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4543 nickserv_load_dict(const char *fname
)
4547 if (!(file
= fopen(fname
, "r"))) {
4548 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4551 while (!feof(file
)) {
4552 fgets(line
, sizeof(line
), file
);
4555 if (line
[strlen(line
)-1] == '\n')
4556 line
[strlen(line
)-1] = 0;
4557 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4560 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4563 static enum reclaim_action
4564 reclaim_action_from_string(const char *str
) {
4566 return RECLAIM_NONE
;
4567 else if (!irccasecmp(str
, "warn"))
4568 return RECLAIM_WARN
;
4569 else if (!irccasecmp(str
, "svsnick"))
4570 return RECLAIM_SVSNICK
;
4571 else if (!irccasecmp(str
, "kill"))
4572 return RECLAIM_KILL
;
4574 return RECLAIM_NONE
;
4578 nickserv_conf_read(void)
4580 dict_t conf_node
, child
;
4583 struct string_list
*strlist
;
4585 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4586 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4589 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4591 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4592 if (nickserv_conf
.valid_handle_regex_set
)
4593 regfree(&nickserv_conf
.valid_handle_regex
);
4595 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4596 nickserv_conf
.valid_handle_regex_set
= !err
;
4597 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4599 nickserv_conf
.valid_handle_regex_set
= 0;
4601 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4602 if (nickserv_conf
.valid_nick_regex_set
)
4603 regfree(&nickserv_conf
.valid_nick_regex
);
4605 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4606 nickserv_conf
.valid_nick_regex_set
= !err
;
4607 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4609 nickserv_conf
.valid_nick_regex_set
= 0;
4611 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4612 if (nickserv_conf
.valid_fakehost_regex_set
)
4613 regfree(&nickserv_conf
.valid_fakehost_regex
);
4615 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4616 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4617 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4619 nickserv_conf
.valid_fakehost_regex_set
= 0;
4621 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4623 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4624 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4625 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4626 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4627 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4628 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4629 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4630 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4631 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4632 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4633 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4634 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4635 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4636 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4637 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4638 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4639 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4640 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4641 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4642 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4643 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4644 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4645 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4646 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4647 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4649 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4650 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4651 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4653 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4654 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4655 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4657 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4658 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4659 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4660 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4661 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4662 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4663 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4664 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4665 if (!nickserv_conf
.disable_nicks
) {
4666 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4667 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4668 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4669 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4670 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4671 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4672 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4673 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4675 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4676 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4677 const char *key
= iter_key(it
), *value
;
4681 if (!strncasecmp(key
, "uc_", 3))
4682 flag
= toupper(key
[3]);
4683 else if (!strncasecmp(key
, "lc_", 3))
4684 flag
= tolower(key
[3]);
4688 if ((pos
= handle_inverse_flags
[flag
])) {
4689 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4690 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4693 if (nickserv_conf
.weak_password_dict
)
4694 dict_delete(nickserv_conf
.weak_password_dict
);
4695 nickserv_conf
.weak_password_dict
= dict_new();
4696 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4697 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4698 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4699 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4701 nickserv_load_dict(str
);
4702 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4703 if (nickserv
&& str
)
4704 NickChange(nickserv
, str
, 0);
4705 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4706 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4707 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4708 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4709 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4710 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4711 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4712 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4713 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4714 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4715 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4716 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4717 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4718 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4719 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4720 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4721 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4722 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4723 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4724 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4726 free_string_list(nickserv_conf
.denied_fakehost_words
);
4727 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4729 strlist
= string_list_copy(strlist
);
4731 strlist
= alloc_string_list(4);
4732 string_list_append(strlist
, strdup("sex"));
4733 string_list_append(strlist
, strdup("fuck"));
4735 nickserv_conf
.denied_fakehost_words
= strlist
;
4737 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4738 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4740 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4741 nickserv_conf
.auto_oper
= str
? str
: "";
4743 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4744 nickserv_conf
.auto_admin
= str
? str
: "";
4746 str
= conf_get_data("server/network", RECDB_QSTRING
);
4747 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4748 if (!nickserv_conf
.auth_policer_params
) {
4749 nickserv_conf
.auth_policer_params
= policer_params_new();
4750 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4751 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4753 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4754 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4755 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4757 str
= database_get_data(conf_node
, KEY_LDAP_ENABLE
, RECDB_QSTRING
);
4758 nickserv_conf
.ldap_enable
= str
? strtoul(str
, NULL
, 0) : 0;
4760 str
= database_get_data(conf_node
, KEY_FORCE_HANDLES_LOWERCASE
, RECDB_QSTRING
);
4761 nickserv_conf
.force_handles_lowercase
= str
? strtol(str
, NULL
, 0) : 0;
4764 if(nickserv_conf
.ldap_enable
> 0) {
4765 /* ldap is enabled but not compiled in - error out */
4766 log_module(MAIN_LOG
, LOG_ERROR
, "ldap is enabled in config, but not compiled in!");
4767 nickserv_conf
.ldap_enable
= 0;
4773 str
= database_get_data(conf_node
, KEY_LDAP_URI
, RECDB_QSTRING
);
4774 nickserv_conf
.ldap_uri
= str
? str
: "";
4776 str
= database_get_data(conf_node
, KEY_LDAP_BASE
, RECDB_QSTRING
);
4777 nickserv_conf
.ldap_base
= str
? str
: "";
4779 str
= database_get_data(conf_node
, KEY_LDAP_DN_FMT
, RECDB_QSTRING
);
4780 nickserv_conf
.ldap_dn_fmt
= str
? str
: "";
4782 str
= database_get_data(conf_node
, KEY_LDAP_VERSION
, RECDB_QSTRING
);
4783 nickserv_conf
.ldap_version
= str
? strtoul(str
, NULL
, 0) : 3;
4785 str
= database_get_data(conf_node
, KEY_LDAP_AUTOCREATE
, RECDB_QSTRING
);
4786 nickserv_conf
.ldap_autocreate
= str
? strtoul(str
, NULL
, 0) : 0;
4788 str
= database_get_data(conf_node
, KEY_LDAP_TIMEOUT
, RECDB_QSTRING
);
4789 nickserv_conf
.ldap_timeout
= str
? strtoul(str
, NULL
, 0) : 5;
4791 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_DN
, RECDB_QSTRING
);
4792 nickserv_conf
.ldap_admin_dn
= str
? str
: "";
4794 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_PASS
, RECDB_QSTRING
);
4795 nickserv_conf
.ldap_admin_pass
= str
? str
: "";
4797 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_ACCOUNT
, RECDB_QSTRING
);
4798 nickserv_conf
.ldap_field_account
= str
? str
: "";
4800 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_PASSWORD
, RECDB_QSTRING
);
4801 nickserv_conf
.ldap_field_password
= str
? str
: "";
4803 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_EMAIL
, RECDB_QSTRING
);
4804 nickserv_conf
.ldap_field_email
= str
? str
: "";
4806 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_DN
, RECDB_QSTRING
);
4807 nickserv_conf
.ldap_oper_group_dn
= str
? str
: "";
4809 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_LEVEL
, RECDB_QSTRING
);
4810 nickserv_conf
.ldap_oper_group_level
= str
? strtoul(str
, NULL
, 0) : 99;
4812 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_GROUP_MEMBER
, RECDB_QSTRING
);
4813 nickserv_conf
.ldap_field_group_member
= str
? str
: "";
4815 free_string_list(nickserv_conf
.ldap_object_classes
);
4816 strlist
= database_get_data(conf_node
, KEY_LDAP_OBJECT_CLASSES
, RECDB_STRING_LIST
);
4818 strlist
= string_list_copy(strlist
);
4820 strlist
= alloc_string_list(4);
4821 string_list_append(strlist
, strdup("top"));
4823 nickserv_conf
.ldap_object_classes
= strlist
;
4830 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4832 char newnick
[NICKLEN
+1];
4841 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4843 case RECLAIM_SVSNICK
:
4845 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4846 } while (GetUserH(newnick
));
4847 irc_svsnick(nickserv
, user
, newnick
);
4850 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4851 irc_kill(nickserv
, user
, msg
);
4857 nickserv_reclaim_p(void *data
) {
4858 struct userNode
*user
= data
;
4859 struct nick_info
*ni
= get_nick_info(user
->nick
);
4861 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4865 check_user_nick(struct userNode
*user
) {
4866 struct nick_info
*ni
;
4867 user
->modes
&= ~FLAGS_REGNICK
;
4868 if (!(ni
= get_nick_info(user
->nick
)))
4870 if (user
->handle_info
== ni
->owner
) {
4871 user
->modes
|= FLAGS_REGNICK
;
4875 if (nickserv_conf
.warn_nick_owned
)
4876 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4877 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4879 if (nickserv_conf
.auto_reclaim_delay
)
4880 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4882 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4887 handle_new_user(struct userNode
*user
)
4889 return check_user_nick(user
);
4893 handle_account(struct userNode
*user
, const char *stamp
)
4895 struct handle_info
*hi
;
4898 #ifdef WITH_PROTOCOL_P10
4899 time_t timestamp
= 0;
4901 colon
= strchr(stamp
, ':');
4902 if(colon
&& colon
[1])
4905 timestamp
= atoi(colon
+1);
4907 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4908 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4910 log_module(MAIN_LOG
, LOG_WARNING
, "%s using account %s but timestamp does not match %s is not %s.", user
->nick
, stamp
, ctime(×tamp
),
4911 ctime(&hi
->registered
));
4915 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4916 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4920 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4923 set_user_handle_info(user
, hi
, 0);
4925 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4930 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4932 struct handle_info
*hi
;
4934 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4935 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4936 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4938 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4939 check_user_nick(user
);
4943 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4945 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4946 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4947 set_user_handle_info(user
, NULL
, 0);
4950 static struct modcmd
*
4951 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4953 if (min_level
> 0) {
4955 sprintf(buf
, "%u", min_level
);
4956 if (must_be_qualified
) {
4957 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4959 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4961 } else if (min_level
== 0) {
4962 if (must_be_qualified
) {
4963 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4965 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4968 if (must_be_qualified
) {
4969 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4971 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4977 nickserv_db_cleanup(void)
4979 unreg_del_user_func(nickserv_remove_user
);
4980 userList_clean(&curr_helpers
);
4981 policer_params_delete(nickserv_conf
.auth_policer_params
);
4982 dict_delete(nickserv_handle_dict
);
4983 dict_delete(nickserv_nick_dict
);
4984 dict_delete(nickserv_opt_dict
);
4985 dict_delete(nickserv_allow_auth_dict
);
4986 dict_delete(nickserv_email_dict
);
4987 dict_delete(nickserv_id_dict
);
4988 dict_delete(nickserv_conf
.weak_password_dict
);
4989 free(auth_func_list
);
4990 free(unreg_func_list
);
4992 free(allowauth_func_list
);
4993 free(handle_merge_func_list
);
4994 free(failpw_func_list
);
4995 if (nickserv_conf
.valid_handle_regex_set
)
4996 regfree(&nickserv_conf
.valid_handle_regex
);
4997 if (nickserv_conf
.valid_nick_regex_set
)
4998 regfree(&nickserv_conf
.valid_nick_regex
);
5001 void handle_loc_auth_oper(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
)) {
5002 if (!*nickserv_conf
.auto_oper
|| !user
->handle_info
)
5005 if (!IsOper(user
)) {
5006 if (*nickserv_conf
.auto_admin
&& user
->handle_info
->opserv_level
>= opserv_conf_admin_level()) {
5007 irc_umode(user
, nickserv_conf
.auto_admin
);
5008 irc_sno(0x1, "%s (%s@%s) is now an IRC Administrator",
5009 user
->nick
, user
->ident
, user
->hostname
);
5010 } else if (*nickserv_conf
.auto_oper
&& user
->handle_info
->opserv_level
) {
5011 irc_umode(user
, nickserv_conf
.auto_oper
);
5012 irc_sno(0x1, "%s (%s@%s) is now an IRC Operator",
5013 user
->nick
, user
->ident
, user
->hostname
);
5019 init_nickserv(const char *nick
)
5021 struct chanNode
*chan
;
5023 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
5024 reg_new_user_func(handle_new_user
);
5025 reg_nick_change_func(handle_nick_change
);
5026 reg_del_user_func(nickserv_remove_user
);
5027 reg_account_func(handle_account
);
5028 reg_auth_func(handle_loc_auth_oper
);
5030 /* set up handle_inverse_flags */
5031 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
5032 for (i
=0; handle_flags
[i
]; i
++) {
5033 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
5034 flag_access_levels
[i
] = 0;
5037 conf_register_reload(nickserv_conf_read
);
5038 nickserv_opt_dict
= dict_new();
5039 nickserv_email_dict
= dict_new();
5041 dict_set_free_keys(nickserv_email_dict
, free
);
5042 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
5044 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
5045 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
5046 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
5047 * a big pain to disable since its nolonger in the config file. ) -Rubin
5049 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
5050 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
5051 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
5052 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
5053 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
5054 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
5055 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
5056 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
5057 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
5058 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
5059 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
5060 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
5061 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
5062 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
5063 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
5064 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
5065 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
5066 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
5067 if (!nickserv_conf
.disable_nicks
) {
5068 /* nick management commands */
5069 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
5070 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
5071 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
5072 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
5073 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
5074 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
5076 if (nickserv_conf
.email_enabled
) {
5077 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
5078 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
5079 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
5080 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
5081 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
5082 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
5084 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
5085 /* ignore commands */
5086 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
5087 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
5088 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
5089 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
5090 /* miscellaneous commands */
5091 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
5092 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
5093 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
5094 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
5095 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
5097 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
5098 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
5099 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
5100 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
5101 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
5102 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
5103 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
5104 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
5105 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
5106 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
5107 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
5108 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
5109 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
5110 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
5111 if (nickserv_conf
.titlehost_suffix
) {
5112 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
5113 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
5115 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
5116 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
5117 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
5118 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
5120 nickserv_handle_dict
= dict_new();
5121 dict_set_free_keys(nickserv_handle_dict
, free
);
5122 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
5124 nickserv_id_dict
= dict_new();
5125 dict_set_free_keys(nickserv_id_dict
, free
);
5127 nickserv_nick_dict
= dict_new();
5128 dict_set_free_data(nickserv_nick_dict
, free
);
5130 nickserv_allow_auth_dict
= dict_new();
5132 userList_init(&curr_helpers
);
5135 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
5136 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
5137 nickserv_service
= service_register(nickserv
);
5139 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
5140 reg_exit_func(nickserv_db_cleanup
);
5141 if(nickserv_conf
.handle_expire_frequency
)
5142 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
5144 if(autojoin_channels
&& nickserv
) {
5145 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
5146 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
5147 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
5151 ldap_do_init(nickserv_conf
);
5154 message_register_table(msgtab
);