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 register_nick(user
->nick
, hi
);
1116 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1119 if (settee
&& (user
!= settee
)) {
1121 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1128 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1130 cookie
->hi
->cookie
= cookie
;
1131 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1134 /* Contributed by the great sneep of afternet ;) */
1135 /* Since this gets used in a URL, we want to avoid stuff that confuses
1136 * email clients such as ] and ?. a-z, 0-9 only.
1138 void genpass(char *str
, int len
)
1143 for(i
= 0; i
< len
; i
++)
1147 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1148 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1156 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1158 struct handle_cookie
*cookie
;
1159 char subject
[128], body
[4096], *misc
;
1160 const char *netname
, *fmt
;
1164 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1168 cookie
= calloc(1, sizeof(*cookie
));
1170 cookie
->type
= type
;
1171 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1173 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1174 /* Adding dedicated password gen function for more control -Rubin */
1175 genpass(cookie
->cookie
, 10);
1177 *inttobase64(cookie->cookie, rand(), 5);
1178 *inttobase64(cookie->cookie+5, rand(), 5);
1181 netname
= nickserv_conf
.network_name
;
1184 switch (cookie
->type
) {
1186 hi
->passwd
[0] = 0; /* invalidate password */
1187 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1188 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1189 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1192 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1194 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1196 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1199 case PASSWORD_CHANGE
:
1200 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1201 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1202 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1204 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1206 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1207 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1210 misc
= hi
->email_addr
;
1211 hi
->email_addr
= cookie
->data
;
1212 #ifdef stupid_verify_old_email
1214 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1215 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1216 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1217 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1218 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1219 sendmail(nickserv
, hi
, subject
, body
, 1);
1220 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1221 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1224 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1225 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1226 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1227 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1228 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1229 sendmail(nickserv
, hi
, subject
, body
, 1);
1231 #ifdef stupid_verify_old_email
1234 hi
->email_addr
= misc
;
1237 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1238 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1239 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1240 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1241 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1244 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1248 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1249 nickserv_bake_cookie(cookie
);
1253 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1255 cookie
->hi
->cookie
= NULL
;
1256 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1257 nickserv_free_cookie(cookie
);
1261 nickserv_free_email_addr(void *data
)
1263 handle_info_list_clean(data
);
1268 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1270 struct handle_info_list
*hil
;
1271 /* Remove from old handle_info_list ... */
1272 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1273 handle_info_list_remove(hil
, hi
);
1274 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1275 hi
->email_addr
= NULL
;
1277 /* Add to the new list.. */
1278 if (new_email_addr
) {
1279 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1280 hil
= calloc(1, sizeof(*hil
));
1281 hil
->tag
= strdup(new_email_addr
);
1282 handle_info_list_init(hil
);
1283 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1285 handle_info_list_append(hil
, hi
);
1286 hi
->email_addr
= hil
->tag
;
1290 static NICKSERV_FUNC(cmd_register
)
1293 struct handle_info
*hi
;
1294 const char *email_addr
, *password
;
1295 char syncpass
[MD5_CRYPT_LENGTH
];
1296 int no_auth
, weblink
;
1298 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1299 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1303 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1304 /* Require the first handle registered to belong to someone +o. */
1305 reply("NSMSG_REQUIRE_OPER");
1309 if (user
->handle_info
) {
1310 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1314 if (IsRegistering(user
)) {
1315 reply("NSMSG_ALREADY_REGISTERING");
1319 if (IsStamped(user
)) {
1320 /* Unauthenticated users might still have been stamped
1321 previously and could therefore have a hidden host;
1322 do not allow them to register a new account. */
1323 reply("NSMSG_STAMPED_REGISTER");
1327 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1329 if(nickserv_conf
.force_handles_lowercase
)
1330 irc_strtolower(argv
[1]);
1331 if (!is_valid_handle(argv
[1])) {
1332 reply("NSMSG_BAD_HANDLE", argv
[1]);
1337 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1338 struct handle_info_list
*hil
;
1341 /* Remember email address. */
1342 email_addr
= argv
[3];
1344 /* Check that the email address looks valid.. */
1345 if (!valid_email(email_addr
)) {
1346 reply("NSMSG_BAD_EMAIL_ADDR");
1350 /* .. and that we are allowed to send to it. */
1351 if ((str
= sendmail_prohibited_address(email_addr
))) {
1352 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1356 /* If we do email verify, make sure we don't spam the address. */
1357 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1359 for (nn
=0; nn
<hil
->used
; nn
++) {
1360 if (hil
->list
[nn
]->cookie
) {
1361 reply("NSMSG_EMAIL_UNACTIVATED");
1365 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1366 reply("NSMSG_EMAIL_OVERUSED");
1379 /* Webregister hack - send URL instead of IRC cookie
1382 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1386 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1388 /* Add any masks they should get. */
1389 if (nickserv_conf
.default_hostmask
) {
1390 string_list_append(hi
->masks
, strdup("*@*"));
1392 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1393 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1394 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1397 /* If they're the first to register, give them level 1000. */
1398 if (dict_size(nickserv_handle_dict
) == 1) {
1399 hi
->opserv_level
= 1000;
1400 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1403 /* Set their email address. */
1406 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1408 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email_addr
)) != LDAP_SUCCESS
) {
1409 /* Falied to update email in ldap, but still
1410 * updated it here.. what should we do? */
1411 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1413 nickserv_set_email_addr(hi
, email_addr
);
1417 nickserv_set_email_addr(hi
, email_addr
);
1420 nickserv_set_email_addr(hi
, email_addr
);
1424 /* If they need to do email verification, tell them. */
1426 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1428 /* Set registering flag.. */
1429 user
->modes
|= FLAGS_REGISTERING
;
1431 if (nickserv_conf
.sync_log
) {
1432 cryptpass(password
, syncpass
);
1434 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1435 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1438 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1441 /* this wont work if email is required .. */
1442 process_adduser_pending(user
);
1447 static NICKSERV_FUNC(cmd_oregister
)
1449 struct userNode
*settee
= NULL
;
1450 struct handle_info
*hi
;
1451 char* account
= NULL
;
1457 NICKSERV_MIN_PARMS(3);
1461 if(nickserv_conf
.force_handles_lowercase
)
1462 irc_strtolower(account
);
1463 if (nickserv_conf
.email_required
) {
1464 NICKSERV_MIN_PARMS(4);
1466 if (argc
>= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1467 if (strchr(argv
[4], '@') || argc
>= 6) /* If @, its mask not nick */
1477 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1478 if (strchr(argv
[3], '@') || argc
>= 5) /* If @, its mask not nick */
1487 /* If they passed a nick, look for that user.. */
1488 if (nick
&& !(settee
= GetUserH(nick
))) {
1489 reply("MSG_NICK_UNKNOWN", argv
[4]);
1492 /* If the setee is already authed, we cant add a 2nd account for them.. */
1493 if (settee
&& settee
->handle_info
) {
1494 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1497 /* If there is no default mask in the conf, and they didn't pass a mask,
1498 * but we did find a user by nick, generate the mask */
1500 if (nickserv_conf
.default_hostmask
)
1503 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1505 reply("NSMSG_REGISTER_BAD_NICKMASK");
1510 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1511 return 0; /* error reply handled by above */
1515 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1517 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email
)) != LDAP_SUCCESS
) {
1518 /* Falied to update email in ldap, but still
1519 * updated it here.. what should we do? */
1520 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1522 nickserv_set_email_addr(hi
, email
);
1526 nickserv_set_email_addr(hi
, email
);
1529 nickserv_set_email_addr(hi
, email
);
1533 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1534 string_list_append(hi
->masks
, mask_canonicalized
);
1537 if (nickserv_conf
.sync_log
)
1538 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1543 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1546 struct userNode
*target
;
1547 char *new_mask
= strdup(pretty_mask(mask
));
1548 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1549 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1550 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1555 string_list_append(hi
->ignores
, new_mask
);
1556 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1558 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1559 irc_silence(target
, new_mask
, 1);
1564 static NICKSERV_FUNC(cmd_addignore
)
1566 NICKSERV_MIN_PARMS(2);
1568 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1571 static NICKSERV_FUNC(cmd_oaddignore
)
1573 struct handle_info
*hi
;
1575 NICKSERV_MIN_PARMS(3);
1576 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1579 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1583 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1586 struct userNode
*target
;
1587 char *pmask
= strdup(pretty_mask(del_mask
));
1588 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1589 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1590 char *old_mask
= hi
->ignores
->list
[i
];
1591 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1592 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1593 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1594 irc_silence(target
, old_mask
, 0);
1601 reply("NSMSG_DELMASK_NOT_FOUND");
1605 static NICKSERV_FUNC(cmd_delignore
)
1607 NICKSERV_MIN_PARMS(2);
1608 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1611 static NICKSERV_FUNC(cmd_odelignore
)
1613 struct handle_info
*hi
;
1614 NICKSERV_MIN_PARMS(3);
1615 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1617 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1620 static NICKSERV_FUNC(cmd_handleinfo
)
1623 unsigned int i
, pos
=0, herelen
;
1624 struct userNode
*target
, *next_un
;
1625 struct handle_info
*hi
;
1626 const char *nsmsg_none
;
1629 if (!(hi
= user
->handle_info
)) {
1630 reply("NSMSG_MUST_AUTH");
1633 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1637 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1638 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1640 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1643 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1644 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1646 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1649 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1650 if (HANDLE_FLAGGED(hi
, FROZEN
))
1651 reply("NSMSG_HANDLEINFO_VACATION");
1653 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1654 struct do_not_register
*dnr
;
1655 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1656 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1657 if (!oper_outranks(cmd
, user
, hi
))
1659 } else if (hi
!= user
->handle_info
) {
1660 reply("NSMSG_HANDLEINFO_END");
1664 if (nickserv_conf
.email_enabled
)
1665 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1669 switch (hi
->cookie
->type
) {
1670 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1671 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1672 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1673 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1674 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1680 unsigned long flen
= 1;
1681 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1683 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1684 if (hi
->flags
& 1 << i
)
1685 flags
[flen
++] = handle_flags
[i
];
1687 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1689 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1692 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1693 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1694 || (hi
->opserv_level
> 0)) {
1695 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1698 if (IsHelping(user
) || IsOper(user
))
1703 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1704 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1709 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1711 if (hi
->last_quit_host
[0])
1712 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1714 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1716 if (nickserv_conf
.disable_nicks
) {
1717 /* nicks disabled; don't show anything about registered nicks */
1718 } else if (hi
->nicks
) {
1719 struct nick_info
*ni
, *next_ni
;
1720 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1721 herelen
= strlen(ni
->nick
);
1722 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1724 goto print_nicks_buff
;
1728 memcpy(buff
+pos
, ni
->nick
, herelen
);
1729 pos
+= herelen
; buff
[pos
++] = ' ';
1733 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1738 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1741 if (hi
->masks
->used
) {
1742 for (i
=0; i
< hi
->masks
->used
; i
++) {
1743 herelen
= strlen(hi
->masks
->list
[i
]);
1744 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1746 goto print_mask_buff
;
1748 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1749 pos
+= herelen
; buff
[pos
++] = ' ';
1750 if (i
+1 == hi
->masks
->used
) {
1753 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1758 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1761 if (hi
->ignores
->used
) {
1762 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1763 herelen
= strlen(hi
->ignores
->list
[i
]);
1764 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1766 goto print_ignore_buff
;
1768 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1769 pos
+= herelen
; buff
[pos
++] = ' ';
1770 if (i
+1 == hi
->ignores
->used
) {
1773 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1778 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1782 struct userData
*channel
, *next
;
1785 for (channel
= hi
->channels
; channel
; channel
= next
) {
1786 next
= channel
->u_next
;
1787 name
= channel
->channel
->channel
->name
;
1788 herelen
= strlen(name
);
1789 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1791 goto print_chans_buff
;
1793 if (IsUserSuspended(channel
))
1795 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1799 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1804 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1807 for (target
= hi
->users
; target
; target
= next_un
) {
1808 herelen
= strlen(target
->nick
);
1809 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1811 goto print_cnick_buff
;
1813 next_un
= target
->next_authed
;
1815 memcpy(buff
+pos
, target
->nick
, herelen
);
1816 pos
+= herelen
; buff
[pos
++] = ' ';
1820 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1825 reply("NSMSG_HANDLEINFO_END");
1829 static NICKSERV_FUNC(cmd_userinfo
)
1831 struct userNode
*target
;
1833 NICKSERV_MIN_PARMS(2);
1834 if (!(target
= GetUserH(argv
[1]))) {
1835 reply("MSG_NICK_UNKNOWN", argv
[1]);
1838 if (target
->handle_info
)
1839 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1841 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1845 static NICKSERV_FUNC(cmd_nickinfo
)
1847 struct nick_info
*ni
;
1849 NICKSERV_MIN_PARMS(2);
1850 if (!(ni
= get_nick_info(argv
[1]))) {
1851 reply("MSG_NICK_UNKNOWN", argv
[1]);
1854 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1858 static NICKSERV_FUNC(cmd_rename_handle
)
1860 struct handle_info
*hi
;
1861 struct userNode
*uNode
;
1865 NICKSERV_MIN_PARMS(3);
1866 if(nickserv_conf
.force_handles_lowercase
)
1867 irc_strtolower(argv
[2]);
1868 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1870 if (!is_valid_handle(argv
[2])) {
1871 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1874 if (get_handle_info(argv
[2])) {
1875 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1878 if(strlen(argv
[2]) > 30)
1880 reply("NMSG_HANDLE_TOLONG", argv
[2], 30);
1884 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1886 if( (rc
= ldap_rename_account(hi
->handle
, argv
[2])) != LDAP_SUCCESS
) {
1887 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1893 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1894 hi
->handle
= strdup(argv
[2]);
1895 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1896 for (nn
=0; nn
<rf_list_used
; nn
++)
1897 rf_list
[nn
](hi
, old_handle
);
1899 if (nickserv_conf
.sync_log
) {
1900 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1901 irc_rename(uNode
, hi
->handle
);
1903 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1906 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1907 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1908 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1914 static failpw_func_t
*failpw_func_list
;
1915 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1918 reg_failpw_func(failpw_func_t func
)
1920 if (failpw_func_used
== failpw_func_size
) {
1921 if (failpw_func_size
) {
1922 failpw_func_size
<<= 1;
1923 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1925 failpw_func_size
= 8;
1926 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1929 failpw_func_list
[failpw_func_used
++] = func
;
1933 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1935 * called by nefariouses enhanced AC login-on-connect code
1938 struct handle_info
*loc_auth(char *handle
, char *password
, char *userhost
)
1940 int pw_arg
, used
, maxlogins
;
1943 struct handle_info
*hi
;
1944 struct userNode
*other
;
1946 int ldap_result
= LDAP_SUCCESS
;
1950 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1954 if(nickserv_conf
.ldap_enable
) {
1955 ldap_result
= ldap_check_auth(handle
, password
);
1956 if(ldap_result
!= LDAP_SUCCESS
) {
1965 if (!checkpass(password
, hi
->passwd
)) {
1970 /* ldap libs are present but we are not using them... */
1971 if( !nickserv_conf
.ldap_enable
) {
1975 if (!checkpass(password
, hi
->passwd
)) {
1979 else if( (!hi
) && ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
1980 /* user not found, but authed to ldap successfully..
1981 * create the account.
1986 /* Add a *@* mask */
1987 /* TODO if userhost is not null, build mask based on that. */
1988 if(nickserv_conf
.default_hostmask
)
1991 return NULL
; /* They dont have a *@* mask so they can't loc */
1993 if(!(hi
= nickserv_register(NULL
, NULL
, handle
, password
, 0))) {
1994 return 0; /* couldn't add the user for some reason */
1997 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
1999 if(nickserv_conf
.email_required
) {
2004 nickserv_set_email_addr(hi
, email
);
2008 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2009 string_list_append(hi
->masks
, mask_canonicalized
);
2011 if(nickserv_conf
.sync_log
)
2012 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, "@", handle
);
2016 /* Still no account, so just fail out */
2021 /* We don't know the users hostname, or anything because they
2022 * havn't registered yet. So we can only allow LOC if your
2023 * account has *@* as a hostmask.
2025 * UPDATE: New nefarious LOC supports u@h
2035 buf
= strdup(userhost
);
2036 ident
= mysep(&buf
, "@");
2037 realhost
= mysep(&buf
, ":");
2038 ip
= mysep(&buf
, ":");
2039 if(!ip
|| !realhost
|| !ident
) {
2041 return NULL
; /* Invalid AC request, just quit */
2043 uh
= malloc(strlen(userhost
));
2044 ui
= malloc(strlen(userhost
));
2045 sprintf(uh
, "%s@%s", ident
, realhost
);
2046 sprintf(ui
, "%s@%s", ident
, ip
);
2047 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2049 if(match_ircglob(uh
, hi
->masks
->list
[ii
])
2050 || match_ircglob(ui
, hi
->masks
->list
[ii
]))
2062 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2064 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
2074 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2078 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2079 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2080 if (++used
>= maxlogins
) {
2084 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2088 static NICKSERV_FUNC(cmd_auth
)
2090 int pw_arg
, used
, maxlogins
;
2091 struct handle_info
*hi
;
2093 struct userNode
*other
;
2095 int ldap_result
= LDAP_OTHER
;
2099 if (user
->handle_info
) {
2100 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2103 if (IsStamped(user
)) {
2104 /* Unauthenticated users might still have been stamped
2105 previously and could therefore have a hidden host;
2106 do not allow them to authenticate. */
2107 reply("NSMSG_STAMPED_AUTH");
2112 if(strchr(argv
[1], '<') || strchr(argv
[1], '>')) {
2113 reply("NSMSG_NO_ANGLEBRACKETS");
2116 if (!is_valid_handle(argv
[1])) {
2117 reply("NSMSG_BAD_HANDLE", argv
[1]);
2121 if(nickserv_conf
.ldap_enable
) {
2122 ldap_result
= ldap_check_auth(argv
[1], argv
[2]);
2123 /* Get the users email address and update it */
2124 if(ldap_result
== LDAP_SUCCESS
) {
2126 if((rc
= ldap_get_user_info(argv
[1], &email
) != LDAP_SUCCESS
))
2128 if(nickserv_conf
.email_required
) {
2129 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc
));
2134 else if(ldap_result
!= LDAP_INVALID_CREDENTIALS
) {
2135 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2141 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
2143 } else if (argc
== 2 && !nickserv_conf
.ldap_enable
) {
2144 if (nickserv_conf
.disable_nicks
) {
2145 if (!(hi
= get_handle_info(user
->nick
))) {
2146 reply("NSMSG_HANDLE_NOT_FOUND");
2150 /* try to look up their handle from their nick */
2151 /* TODO: handle ldap auth on nickserv style networks, too */
2152 struct nick_info
*ni
;
2153 ni
= get_nick_info(user
->nick
);
2155 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
2162 reply("MSG_MISSING_PARAMS", argv
[0]);
2163 svccmd_send_help_brief(user
, nickserv
, cmd
);
2168 if(nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2169 /* user not found, but authed to ldap successfully..
2170 * create the account.
2173 if(!(hi
= nickserv_register(user
, NULL
, argv
[1], argv
[2], 0))) {
2174 reply("NSMSG_UNABLE_TO_ADD");
2175 return 0; /* couldn't add the user for some reason */
2177 /* Add a *@* mask */
2178 if(nickserv_conf
.default_hostmask
)
2181 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2184 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2185 string_list_append(hi
->masks
, mask_canonicalized
);
2188 nickserv_set_email_addr(hi
, email
);
2191 if(nickserv_conf
.sync_log
)
2192 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
);
2196 reply("NSMSG_HANDLE_NOT_FOUND");
2202 /* Responses from here on look up the language used by the handle they asked about. */
2203 passwd
= argv
[pw_arg
];
2204 if (!valid_user_for(user
, hi
)) {
2205 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
2206 send_message_type(4, user
, cmd
->parent
->bot
,
2207 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
2210 send_message_type(4, user
, cmd
->parent
->bot
,
2211 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
2213 argv
[pw_arg
] = "BADMASK";
2217 if( ( nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_INVALID_CREDENTIALS
) ||
2218 ( (!nickserv_conf
.ldap_enable
) && (!checkpass(passwd
, hi
->passwd
)) ) ) {
2220 if (!checkpass(passwd
, hi
->passwd
)) {
2223 send_message_type(4, user
, cmd
->parent
->bot
,
2224 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
2225 argv
[pw_arg
] = "BADPASS";
2226 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
2227 if (nickserv_conf
.autogag_enabled
) {
2228 if (!user
->auth_policer
.params
) {
2229 user
->auth_policer
.last_req
= now
;
2230 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
2232 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
2234 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
2235 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
2236 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2238 argv
[pw_arg
] = "GAGGED";
2243 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2244 send_message_type(4, user
, cmd
->parent
->bot
,
2245 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2246 argv
[pw_arg
] = "SUSPENDED";
2249 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2250 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2251 if (++used
>= maxlogins
) {
2252 send_message_type(4, user
, cmd
->parent
->bot
,
2253 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2255 argv
[pw_arg
] = "MAXLOGINS";
2260 set_user_handle_info(user
, hi
, 1);
2261 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2262 reply("NSMSG_PLEASE_SET_EMAIL");
2263 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2264 reply("NSMSG_WEAK_PASSWORD");
2265 if (hi
->passwd
[0] != '$')
2266 cryptpass(passwd
, hi
->passwd
);
2268 /* If a channel was waiting for this user to auth,
2269 * finish adding them */
2270 process_adduser_pending(user
);
2272 reply("NSMSG_AUTH_SUCCESS");
2275 /* Set +x if autohide is on */
2276 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2277 irc_umode(user
, "+x");
2279 if(!IsOper(user
)) /* If they arnt already opered.. */
2281 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2282 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2284 irc_umode(user
,nickserv_conf
.auto_admin
);
2285 reply("NSMSG_AUTO_OPER_ADMIN");
2287 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2289 irc_umode(user
,nickserv_conf
.auto_oper
);
2290 reply("NSMSG_AUTO_OPER");
2294 /* Wipe out the pass for the logs */
2295 argv
[pw_arg
] = "****";
2299 static allowauth_func_t
*allowauth_func_list
;
2300 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2303 reg_allowauth_func(allowauth_func_t func
)
2305 if (allowauth_func_used
== allowauth_func_size
) {
2306 if (allowauth_func_size
) {
2307 allowauth_func_size
<<= 1;
2308 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2310 allowauth_func_size
= 8;
2311 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2314 allowauth_func_list
[allowauth_func_used
++] = func
;
2317 static NICKSERV_FUNC(cmd_allowauth
)
2319 struct userNode
*target
;
2320 struct handle_info
*hi
;
2323 NICKSERV_MIN_PARMS(2);
2324 if (!(target
= GetUserH(argv
[1]))) {
2325 reply("MSG_NICK_UNKNOWN", argv
[1]);
2328 if (target
->handle_info
) {
2329 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2332 if (IsStamped(target
)) {
2333 /* Unauthenticated users might still have been stamped
2334 previously and could therefore have a hidden host;
2335 do not allow them to authenticate to an account. */
2336 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2341 else if (!(hi
= get_handle_info(argv
[2]))) {
2342 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2346 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2347 reply("MSG_USER_OUTRANKED", hi
->handle
);
2350 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2351 || (hi
->opserv_level
> 0))
2352 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2353 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2356 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2357 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2358 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2359 if (nickserv_conf
.email_enabled
)
2360 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2362 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2363 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2365 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2367 for (n
=0; n
<allowauth_func_used
; n
++)
2368 allowauth_func_list
[n
](user
, target
, hi
);
2372 static NICKSERV_FUNC(cmd_authcookie
)
2374 struct handle_info
*hi
;
2376 NICKSERV_MIN_PARMS(2);
2377 if (user
->handle_info
) {
2378 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2381 if (IsStamped(user
)) {
2382 /* Unauthenticated users might still have been stamped
2383 previously and could therefore have a hidden host;
2384 do not allow them to authenticate to an account. */
2385 reply("NSMSG_STAMPED_AUTHCOOKIE");
2388 if (!(hi
= get_handle_info(argv
[1]))) {
2389 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2392 if (!hi
->email_addr
) {
2393 reply("MSG_SET_EMAIL_ADDR");
2396 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2400 static NICKSERV_FUNC(cmd_delcookie
)
2402 struct handle_info
*hi
;
2404 hi
= user
->handle_info
;
2406 reply("NSMSG_NO_COOKIE");
2409 switch (hi
->cookie
->type
) {
2412 reply("NSMSG_MUST_TIME_OUT");
2415 nickserv_eat_cookie(hi
->cookie
);
2416 reply("NSMSG_ATE_COOKIE");
2422 static NICKSERV_FUNC(cmd_odelcookie
)
2424 struct handle_info
*hi
;
2426 NICKSERV_MIN_PARMS(2);
2428 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2432 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2436 switch (hi
->cookie
->type
) {
2438 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2439 if (nickserv_conf
.sync_log
)
2440 SyncLog("ACCOUNTACC %s", hi
->handle
);
2442 case PASSWORD_CHANGE
:
2443 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2444 if (nickserv_conf
.sync_log
)
2445 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2448 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2449 if (nickserv_conf
.sync_log
)
2450 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2453 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2455 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2456 /* Falied to update email in ldap, but still
2457 * updated it here.. what should we do? */
2458 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2460 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2464 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2467 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2469 if (nickserv_conf
.sync_log
)
2470 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2473 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2474 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2478 nickserv_eat_cookie(hi
->cookie
);
2479 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2484 static NICKSERV_FUNC(cmd_resetpass
)
2486 struct handle_info
*hi
;
2487 char crypted
[MD5_CRYPT_LENGTH
];
2490 NICKSERV_MIN_PARMS(3);
2491 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2495 if (user
->handle_info
) {
2496 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2499 if (IsStamped(user
)) {
2500 /* Unauthenticated users might still have been stamped
2501 previously and could therefore have a hidden host;
2502 do not allow them to activate an account. */
2503 reply("NSMSG_STAMPED_RESETPASS");
2506 if (!(hi
= get_handle_info(argv
[1]))) {
2507 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2510 if (!hi
->email_addr
) {
2511 reply("MSG_SET_EMAIL_ADDR");
2514 cryptpass(argv
[2], crypted
);
2516 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2520 static NICKSERV_FUNC(cmd_cookie
)
2522 struct handle_info
*hi
;
2525 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2528 NICKSERV_MIN_PARMS(3);
2529 if (!(hi
= get_handle_info(argv
[1]))) {
2530 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2536 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2537 reply("NSMSG_HANDLE_SUSPENDED");
2542 reply("NSMSG_NO_COOKIE");
2546 /* Check validity of operation before comparing cookie to
2547 * prohibit guessing by authed users. */
2548 if (user
->handle_info
2549 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2550 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2551 reply("NSMSG_CANNOT_COOKIE");
2555 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2556 reply("NSMSG_BAD_COOKIE");
2560 switch (hi
->cookie
->type
) {
2563 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2565 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2566 /* Falied to update email in ldap, but still
2567 * updated it here.. what should we do? */
2568 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2573 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2574 set_user_handle_info(user
, hi
, 1);
2575 reply("NSMSG_HANDLE_ACTIVATED");
2576 if (nickserv_conf
.sync_log
)
2577 SyncLog("ACCOUNTACC %s", hi
->handle
);
2579 case PASSWORD_CHANGE
:
2581 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2583 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2584 /* Falied to update email in ldap, but still
2585 * updated it here.. what should we do? */
2586 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2591 set_user_handle_info(user
, hi
, 1);
2592 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2593 reply("NSMSG_PASSWORD_CHANGED");
2594 if (nickserv_conf
.sync_log
)
2595 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2599 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2601 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2602 /* Falied to update email in ldap, but still
2603 * updated it here.. what should we do? */
2604 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2609 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2611 * This should only happen if an OREGISTER was sent. Require
2612 * email must be enabled! - SiRVulcaN
2614 if (nickserv_conf
.sync_log
)
2615 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2618 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2619 reply("NSMSG_EMAIL_CHANGED");
2620 if (nickserv_conf
.sync_log
)
2621 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2624 set_user_handle_info(user
, hi
, 1);
2625 reply("NSMSG_AUTH_SUCCESS");
2628 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2629 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2633 nickserv_eat_cookie(hi
->cookie
);
2635 process_adduser_pending(user
);
2640 static NICKSERV_FUNC(cmd_oregnick
) {
2642 struct handle_info
*target
;
2643 struct nick_info
*ni
;
2645 NICKSERV_MIN_PARMS(3);
2646 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2649 if (!is_registerable_nick(nick
)) {
2650 reply("NSMSG_BAD_NICK", nick
);
2653 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2655 reply("NSMSG_NICK_EXISTS", nick
);
2658 register_nick(nick
, target
);
2659 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2663 static NICKSERV_FUNC(cmd_regnick
) {
2665 struct nick_info
*ni
;
2667 if (!is_registerable_nick(user
->nick
)) {
2668 reply("NSMSG_BAD_NICK", user
->nick
);
2671 /* count their nicks, see if it's too many */
2672 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2673 if (n
>= nickserv_conf
.nicks_per_handle
) {
2674 reply("NSMSG_TOO_MANY_NICKS");
2677 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2679 reply("NSMSG_NICK_EXISTS", user
->nick
);
2682 register_nick(user
->nick
, user
->handle_info
);
2683 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2687 static NICKSERV_FUNC(cmd_pass
)
2689 struct handle_info
*hi
;
2690 char *old_pass
, *new_pass
;
2691 char crypted
[MD5_CRYPT_LENGTH
+1];
2696 NICKSERV_MIN_PARMS(3);
2697 hi
= user
->handle_info
;
2701 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2704 if(nickserv_conf
.ldap_enable
) {
2705 ldap_result
= ldap_check_auth(hi
->handle
, old_pass
);
2706 if(ldap_result
!= LDAP_SUCCESS
) {
2707 if(ldap_result
== LDAP_INVALID_CREDENTIALS
)
2708 reply("NSMSG_PASSWORD_INVALID");
2710 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2715 if (!checkpass(old_pass
, hi
->passwd
)) {
2716 argv
[1] = "BADPASS";
2717 reply("NSMSG_PASSWORD_INVALID");
2720 cryptpass(new_pass
, crypted
);
2722 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2724 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
2725 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2730 //cryptpass(new_pass, hi->passwd);
2731 strcpy(hi
->passwd
, crypted
);
2732 if (nickserv_conf
.sync_log
)
2733 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2735 reply("NSMSG_PASS_SUCCESS");
2740 nickserv_addmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2743 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2744 for (i
=0; i
<hi
->masks
->used
; i
++) {
2745 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2746 reply("NSMSG_ADDMASK_ALREADY", new_mask
);
2751 string_list_append(hi
->masks
, new_mask
);
2752 reply("NSMSG_ADDMASK_SUCCESS", new_mask
);
2756 static NICKSERV_FUNC(cmd_addmask
)
2759 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2760 int res
= nickserv_addmask(cmd
, user
, user
->handle_info
, mask
);
2764 if (!is_gline(argv
[1])) {
2765 reply("NSMSG_MASK_INVALID", argv
[1]);
2768 return nickserv_addmask(cmd
, user
, user
->handle_info
, argv
[1]);
2772 static NICKSERV_FUNC(cmd_oaddmask
)
2774 struct handle_info
*hi
;
2776 NICKSERV_MIN_PARMS(3);
2777 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2779 return nickserv_addmask(cmd
, user
, hi
, argv
[2]);
2783 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2786 for (i
=0; i
<hi
->masks
->used
; i
++) {
2787 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2788 char *old_mask
= hi
->masks
->list
[i
];
2789 if (hi
->masks
->used
== 1) {
2790 reply("NSMSG_DELMASK_NOTLAST");
2793 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2794 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2799 reply("NSMSG_DELMASK_NOT_FOUND");
2803 static NICKSERV_FUNC(cmd_delmask
)
2805 NICKSERV_MIN_PARMS(2);
2806 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1]);
2809 static NICKSERV_FUNC(cmd_odelmask
)
2811 struct handle_info
*hi
;
2812 NICKSERV_MIN_PARMS(3);
2813 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2815 return nickserv_delmask(cmd
, user
, hi
, argv
[2]);
2819 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2820 unsigned int nn
, add
= 1, pos
;
2821 unsigned long added
, removed
, flag
;
2823 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2825 case '+': add
= 1; break;
2826 case '-': add
= 0; break;
2828 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2829 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2832 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2833 /* cheesy avoidance of looking up the flag name.. */
2834 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2837 flag
= 1 << (pos
- 1);
2839 added
|= flag
, removed
&= ~flag
;
2841 removed
|= flag
, added
&= ~flag
;
2846 *premoved
= removed
;
2851 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2853 unsigned long before
, after
, added
, removed
;
2854 struct userNode
*uNode
;
2856 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2857 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2859 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2860 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2862 /* Strip helping flag if they're only a support helper and not
2863 * currently in #support. */
2864 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2865 struct channelList
*schannels
;
2867 schannels
= chanserv_support_channels();
2868 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2869 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2870 if (GetUserMode(schannels
->list
[ii
], uNode
))
2872 if (ii
< schannels
->used
)
2876 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2879 if (after
&& !before
) {
2880 /* Add user to current helper list. */
2881 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2882 userList_append(&curr_helpers
, uNode
);
2883 } else if (!after
&& before
) {
2884 /* Remove user from current helper list. */
2885 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2886 userList_remove(&curr_helpers
, uNode
);
2893 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2897 char *set_display
[] = {
2898 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2899 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2900 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2903 reply("NSMSG_SETTING_LIST");
2904 reply("NSMSG_SETTING_LIST_HEADER");
2906 /* Do this so options are presented in a consistent order. */
2907 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2908 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2909 opt(cmd
, user
, hi
, override
, 0, NULL
);
2910 reply("NSMSG_SETTING_LIST_END");
2913 static NICKSERV_FUNC(cmd_set
)
2915 struct handle_info
*hi
;
2918 hi
= user
->handle_info
;
2920 set_list(cmd
, user
, hi
, 0);
2923 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2924 reply("NSMSG_INVALID_OPTION", argv
[1]);
2927 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2930 static NICKSERV_FUNC(cmd_oset
)
2932 struct handle_info
*hi
;
2935 NICKSERV_MIN_PARMS(2);
2937 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2941 set_list(cmd
, user
, hi
, 0);
2945 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2946 reply("NSMSG_INVALID_OPTION", argv
[2]);
2950 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
2953 static OPTION_FUNC(opt_info
)
2957 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2959 hi
->infoline
= NULL
;
2961 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2965 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2966 reply("NSMSG_SET_INFO", info
);
2970 static OPTION_FUNC(opt_width
)
2973 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2975 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2976 hi
->screen_width
= MIN_LINE_SIZE
;
2977 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2978 hi
->screen_width
= MAX_LINE_SIZE
;
2980 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
2984 static OPTION_FUNC(opt_tablewidth
)
2987 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2989 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2990 hi
->table_width
= MIN_LINE_SIZE
;
2991 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2992 hi
->table_width
= MAX_LINE_SIZE
;
2994 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2998 static OPTION_FUNC(opt_color
)
3001 if (enabled_string(argv
[1]))
3002 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
3003 else if (disabled_string(argv
[1]))
3004 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
3006 reply("MSG_INVALID_BINARY", argv
[1]);
3011 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
3015 static OPTION_FUNC(opt_privmsg
)
3018 if (enabled_string(argv
[1]))
3019 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
3020 else if (disabled_string(argv
[1]))
3021 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
3023 reply("MSG_INVALID_BINARY", argv
[1]);
3028 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
3032 static OPTION_FUNC(opt_autohide
)
3035 if (enabled_string(argv
[1]))
3036 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
3037 else if (disabled_string(argv
[1]))
3038 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
3040 reply("MSG_INVALID_BINARY", argv
[1]);
3045 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
3049 static OPTION_FUNC(opt_style
)
3054 if (!irccasecmp(argv
[1], "Clean"))
3055 hi
->userlist_style
= HI_STYLE_CLEAN
;
3056 else if (!irccasecmp(argv
[1], "Advanced"))
3057 hi
->userlist_style
= HI_STYLE_ADVANCED
;
3058 else if (!irccasecmp(argv
[1], "Classic"))
3059 hi
->userlist_style
= HI_STYLE_CLASSIC
;
3060 else /* Default to normal */
3061 hi
->userlist_style
= HI_STYLE_NORMAL
;
3062 } /* TODO: give error if unknow style is chosen */
3064 switch (hi
->userlist_style
) {
3065 case HI_STYLE_ADVANCED
:
3068 case HI_STYLE_CLASSIC
:
3071 case HI_STYLE_CLEAN
:
3074 case HI_STYLE_NORMAL
:
3079 reply("NSMSG_SET_STYLE", style
);
3083 static OPTION_FUNC(opt_announcements
)
3088 if (enabled_string(argv
[1]))
3089 hi
->announcements
= 'y';
3090 else if (disabled_string(argv
[1]))
3091 hi
->announcements
= 'n';
3092 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
3093 hi
->announcements
= '?';
3095 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
3100 switch (hi
->announcements
) {
3101 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
3102 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
3103 case '?': choice
= "default"; break;
3104 default: choice
= "unknown"; break;
3106 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
3110 static OPTION_FUNC(opt_password
)
3112 char crypted
[MD5_CRYPT_LENGTH
+1];
3117 reply("NSMSG_USE_CMD_PASS");
3121 cryptpass(argv
[1], crypted
);
3123 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3125 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
3126 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3131 strcpy(hi
->passwd
, crypted
);
3132 if (nickserv_conf
.sync_log
)
3133 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
3135 reply("NSMSG_SET_PASSWORD", "***");
3139 static OPTION_FUNC(opt_flags
)
3142 unsigned int ii
, flen
;
3145 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3150 nickserv_apply_flags(user
, hi
, argv
[1]);
3152 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
3153 if (hi
->flags
& (1 << ii
))
3154 flags
[flen
++] = handle_flags
[ii
];
3157 reply("NSMSG_SET_FLAGS", flags
);
3159 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
3163 static OPTION_FUNC(opt_email
)
3167 if (!valid_email(argv
[1])) {
3168 reply("NSMSG_BAD_EMAIL_ADDR");
3171 if ((str
= sendmail_prohibited_address(argv
[1]))) {
3172 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
3175 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
3176 reply("NSMSG_EMAIL_SAME");
3178 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
3181 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3183 if((rc
= ldap_do_modify(hi
->handle
, NULL
, argv
[1])) != LDAP_SUCCESS
) {
3184 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3189 nickserv_set_email_addr(hi
, argv
[1]);
3191 nickserv_eat_cookie(hi
->cookie
);
3192 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3195 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3199 static OPTION_FUNC(opt_maxlogins
)
3201 unsigned char maxlogins
;
3203 maxlogins
= strtoul(argv
[1], NULL
, 0);
3204 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
3205 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
3208 hi
->maxlogins
= maxlogins
;
3210 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
3211 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
3215 static OPTION_FUNC(opt_advanced
)
3218 if (enabled_string(argv
[1]))
3219 HANDLE_SET_FLAG(hi
, ADVANCED
);
3220 else if (disabled_string(argv
[1]))
3221 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
3223 reply("MSG_INVALID_BINARY", argv
[1]);
3228 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
3232 static OPTION_FUNC(opt_language
)
3234 struct language
*lang
;
3236 lang
= language_find(argv
[1]);
3237 if (irccasecmp(lang
->name
, argv
[1]))
3238 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
3239 hi
->language
= lang
;
3241 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
3245 /* Called from opserv from cmd_access */
3247 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
3248 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
3250 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
3251 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
3252 && (user
->handle_info
->opserv_level
< 1000))) {
3253 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
3256 if ((user
->handle_info
->opserv_level
< new_level
)
3257 || ((user
->handle_info
->opserv_level
== new_level
)
3258 && (user
->handle_info
->opserv_level
< 1000))) {
3259 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
3262 if (user
->handle_info
== target
) {
3263 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
3267 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_oper_group_dn
&& nickserv_conf
.ldap_admin_dn
) {
3269 if(new_level
> nickserv_conf
.ldap_oper_group_level
)
3270 rc
= ldap_add2group(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3272 rc
= ldap_delfromgroup(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3273 if(rc
!= LDAP_SUCCESS
&& rc
!= LDAP_TYPE_OR_VALUE_EXISTS
&& rc
!= LDAP_NO_SUCH_ATTRIBUTE
) {
3274 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3279 if (target
->opserv_level
== new_level
)
3281 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
3282 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
3283 target
->opserv_level
= new_level
;
3287 static OPTION_FUNC(opt_level
)
3292 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3296 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
3297 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
3301 static OPTION_FUNC(opt_epithet
)
3303 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
3305 struct userNode
*target
, *next_un
;
3308 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3312 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
3316 if ((epithet
[0] == '*') && !epithet
[1])
3319 hi
->epithet
= strdup(epithet
);
3321 for (target
= hi
->users
; target
; target
= next_un
) {
3322 irc_swhois(nickserv
, target
, hi
->epithet
);
3324 next_un
= target
->next_authed
;
3329 reply("NSMSG_SET_EPITHET", hi
->epithet
);
3331 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
3335 static OPTION_FUNC(opt_title
)
3341 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
3343 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3348 if(!strcmp(title
, "*")) {
3350 hi
->fakehost
= NULL
;
3353 if (strchr(title
, '.')) {
3354 reply("NSMSG_TITLE_INVALID");
3357 /* Alphanumeric titles only. */
3358 for(sptr
= title
; *sptr
; sptr
++) {
3359 if(!isalnum(*sptr
) && *sptr
!= '-') {
3360 reply("NSMSG_TITLE_INVALID");
3364 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
3365 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3366 reply("NSMSG_TITLE_TRUNCATED");
3370 hi
->fakehost
= malloc(strlen(title
)+2);
3371 hi
->fakehost
[0] = '.';
3372 strcpy(hi
->fakehost
+1, title
);
3375 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3376 title
= hi
->fakehost
+ 1;
3378 /* If theres no title set then the default title will therefore
3379 be the first part of hidden_host in x3.conf, so for
3380 consistency with opt_fakehost we will print this here.
3381 This isnt actually used in P10, its just handled to keep from crashing... */
3382 char *hs
, *hidden_suffix
, *rest
;
3384 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3385 hidden_suffix
= strdup(hs
);
3387 /* Yes we do this twice */
3388 if((rest
= strchr(hidden_suffix
, '.')))
3391 title
= hidden_suffix
;
3395 /* A lame default if someone configured hidden_host to something lame */
3396 title
= strdup("users");
3397 free(hidden_suffix
);
3403 none
= user_find_message(user
, "MSG_NONE");
3404 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3409 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3413 // check for a dot in the vhost
3414 if(strchr(vhost
, '.') == NULL
) {
3415 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3419 // check for a @ in the vhost
3420 if(strchr(vhost
, '@') != NULL
) {
3421 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3425 // check for denied words, inspired by monk at paki.sex
3426 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3427 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3428 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3433 // check for ircu's HOSTLEN length.
3434 if(strlen(vhost
) >= HOSTLEN
) {
3435 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3439 /* This can be handled by the regex now if desired.
3440 if (vhost[strspn(vhost, "0123456789.")]) {
3441 hostname = vhost + strlen(vhost);
3442 for (depth = 1; depth && (hostname > vhost); depth--) {
3444 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3447 if (*hostname == '.') hostname++; * advance past last dot we saw *
3448 if(strlen(hostname) > 4) {
3449 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3454 /* test either regex or as valid handle */
3455 if (nickserv_conf
.valid_fakehost_regex_set
) {
3456 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3459 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3460 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3462 if(err
== REG_NOMATCH
) {
3463 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3472 static OPTION_FUNC(opt_fakehost
)
3476 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3478 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3483 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3484 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3487 if (!strcmp(fake
, "*")) {
3490 hi
->fakehost
= NULL
;
3493 else if (!check_vhost(argv
[1], user
, cmd
)) {
3494 /* check_vhost takes care of error reply */
3500 hi
->fakehost
= strdup(fake
);
3503 fake
= hi
->fakehost
;
3505 fake
= generate_fakehost(hi
);
3507 /* Tell them we set the host */
3509 fake
= user_find_message(user
, "MSG_NONE");
3510 reply("NSMSG_SET_FAKEHOST", fake
);
3514 static OPTION_FUNC(opt_note
)
3517 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3522 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3527 if ((text
[0] == '*') && !text
[1])
3530 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3535 reply("NSMSG_SET_NOTE", hi
->note
? hi
->note
->note
: user_find_message(user
, "MSG_NONE"));
3539 static NICKSERV_FUNC(cmd_reclaim
)
3541 struct handle_info
*hi
;
3542 struct nick_info
*ni
;
3543 struct userNode
*victim
;
3545 NICKSERV_MIN_PARMS(2);
3546 hi
= user
->handle_info
;
3547 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3549 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3552 if (ni
->owner
!= user
->handle_info
) {
3553 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3556 victim
= GetUserH(ni
->nick
);
3558 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3561 if (victim
== user
) {
3562 reply("NSMSG_NICK_USER_YOU");
3565 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3566 switch (nickserv_conf
.reclaim_action
) {
3567 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3568 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3569 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3570 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3575 static NICKSERV_FUNC(cmd_unregnick
)
3578 struct handle_info
*hi
;
3579 struct nick_info
*ni
;
3581 hi
= user
->handle_info
;
3582 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3583 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3585 reply("NSMSG_UNKNOWN_NICK", nick
);
3588 if (hi
!= ni
->owner
) {
3589 reply("NSMSG_NOT_YOUR_NICK", nick
);
3592 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3597 static NICKSERV_FUNC(cmd_ounregnick
)
3599 struct nick_info
*ni
;
3601 NICKSERV_MIN_PARMS(2);
3602 if (!(ni
= get_nick_info(argv
[1]))) {
3603 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3606 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3607 reply("MSG_USER_OUTRANKED", ni
->nick
);
3610 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3615 static NICKSERV_FUNC(cmd_unregister
)
3617 struct handle_info
*hi
;
3620 NICKSERV_MIN_PARMS(2);
3621 hi
= user
->handle_info
;
3624 if (checkpass(passwd
, hi
->passwd
)) {
3625 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3630 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3631 reply("NSMSG_PASSWORD_INVALID");
3636 static NICKSERV_FUNC(cmd_ounregister
)
3638 struct handle_info
*hi
;
3640 NICKSERV_MIN_PARMS(2);
3641 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
3643 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3649 static NICKSERV_FUNC(cmd_status
)
3651 if (nickserv_conf
.disable_nicks
) {
3652 reply("NSMSG_GLOBAL_STATS_NONICK",
3653 dict_size(nickserv_handle_dict
));
3655 if (user
->handle_info
) {
3657 struct nick_info
*ni
;
3658 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3659 reply("NSMSG_HANDLE_STATS", cnt
);
3661 reply("NSMSG_HANDLE_NONE");
3663 reply("NSMSG_GLOBAL_STATS",
3664 dict_size(nickserv_handle_dict
),
3665 dict_size(nickserv_nick_dict
));
3670 static NICKSERV_FUNC(cmd_ghost
)
3672 struct userNode
*target
;
3673 char reason
[MAXLEN
];
3675 NICKSERV_MIN_PARMS(2);
3676 if (!(target
= GetUserH(argv
[1]))) {
3677 reply("MSG_NICK_UNKNOWN", argv
[1]);
3680 if (target
== user
) {
3681 reply("NSMSG_CANNOT_GHOST_SELF");
3684 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3685 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3688 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3689 DelUser(target
, nickserv
, 1, reason
);
3690 reply("NSMSG_GHOST_KILLED", argv
[1]);
3694 static NICKSERV_FUNC(cmd_vacation
)
3696 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3697 reply("NSMSG_ON_VACATION");
3702 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3704 struct handle_info
*hi
;
3707 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3709 saxdb_start_record(ctx
, iter_key(it
), 0);
3710 if (hi
->announcements
!= '?') {
3711 flags
[0] = hi
->announcements
;
3713 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3716 struct handle_cookie
*cookie
= hi
->cookie
;
3719 switch (cookie
->type
) {
3720 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3721 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3722 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3723 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3724 default: type
= NULL
; break;
3727 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3728 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3729 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3731 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3732 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3733 saxdb_end_record(ctx
);
3737 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3739 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3741 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3742 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3743 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3744 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3745 saxdb_end_record(ctx
);
3749 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3753 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3754 if (hi
->flags
& (1 << ii
))
3755 flags
[flen
++] = handle_flags
[ii
];
3757 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3760 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3761 if (hi
->last_quit_host
[0])
3762 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3763 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3764 if (hi
->masks
->used
)
3765 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3766 if (hi
->ignores
->used
)
3767 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3769 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3771 struct string_list
*slist
;
3772 struct nick_info
*ni
;
3774 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3775 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3776 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3780 if (hi
->opserv_level
)
3781 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3782 if (hi
->language
!= lang_C
)
3783 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3784 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3785 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3786 if (hi
->screen_width
)
3787 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3788 if (hi
->table_width
)
3789 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3790 flags
[0] = hi
->userlist_style
;
3792 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3793 saxdb_end_record(ctx
);
3799 static handle_merge_func_t
*handle_merge_func_list
;
3800 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3803 reg_handle_merge_func(handle_merge_func_t func
)
3805 if (handle_merge_func_used
== handle_merge_func_size
) {
3806 if (handle_merge_func_size
) {
3807 handle_merge_func_size
<<= 1;
3808 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3810 handle_merge_func_size
= 8;
3811 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3814 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3817 static NICKSERV_FUNC(cmd_merge
)
3819 struct handle_info
*hi_from
, *hi_to
;
3820 struct userNode
*last_user
;
3821 struct userData
*cList
, *cListNext
;
3822 unsigned int ii
, jj
, n
;
3824 NICKSERV_MIN_PARMS(3);
3826 if (!(hi_from
= get_victim_oper(cmd
, user
, argv
[1])))
3828 if (!(hi_to
= get_victim_oper(cmd
, user
, argv
[2])))
3830 if (hi_to
== hi_from
) {
3831 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3835 for (n
=0; n
<handle_merge_func_used
; n
++)
3836 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3838 /* Append "from" handle's nicks to "to" handle's nick list. */
3840 struct nick_info
*last_ni
;
3841 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3842 last_ni
->next
= hi_from
->nicks
;
3844 while (hi_from
->nicks
) {
3845 hi_from
->nicks
->owner
= hi_to
;
3846 hi_from
->nicks
= hi_from
->nicks
->next
;
3849 /* Merge the hostmasks. */
3850 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3851 char *mask
= hi_from
->masks
->list
[ii
];
3852 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3853 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3855 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3856 string_list_append(hi_to
->masks
, strdup(mask
));
3859 /* Merge the ignores. */
3860 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3861 char *ignore
= hi_from
->ignores
->list
[ii
];
3862 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3863 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3865 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3866 string_list_append(hi_to
->ignores
, strdup(ignore
));
3869 /* Merge the lists of authed users. */
3871 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3872 last_user
->next_authed
= hi_from
->users
;
3874 hi_to
->users
= hi_from
->users
;
3876 /* Repoint the old "from" handle's users. */
3877 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3878 last_user
->handle_info
= hi_to
;
3880 hi_from
->users
= NULL
;
3882 /* Merge channel userlists. */
3883 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3884 struct userData
*cList2
;
3885 cListNext
= cList
->u_next
;
3886 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3887 if (cList
->channel
== cList2
->channel
)
3889 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3890 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
);
3891 /* keep cList2 in hi_to; remove cList from hi_from */
3892 del_channel_user(cList
, 1);
3895 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
);
3896 /* remove the lower-ranking cList2 from hi_to */
3897 del_channel_user(cList2
, 1);
3899 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3901 /* cList needs to be moved from hi_from to hi_to */
3902 cList
->handle
= hi_to
;
3903 /* Remove from linked list for hi_from */
3904 assert(!cList
->u_prev
);
3905 hi_from
->channels
= cList
->u_next
;
3907 cList
->u_next
->u_prev
= cList
->u_prev
;
3908 /* Add to linked list for hi_to */
3909 cList
->u_prev
= NULL
;
3910 cList
->u_next
= hi_to
->channels
;
3911 if (hi_to
->channels
)
3912 hi_to
->channels
->u_prev
= cList
;
3913 hi_to
->channels
= cList
;
3917 /* Do they get an OpServ level promotion? */
3918 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3919 hi_to
->opserv_level
= hi_from
->opserv_level
;
3921 /* What about last seen time? */
3922 if (hi_from
->lastseen
> hi_to
->lastseen
)
3923 hi_to
->lastseen
= hi_from
->lastseen
;
3925 /* Does a fakehost carry over? (This intentionally doesn't set it
3926 * for users previously attached to hi_to. They'll just have to
3929 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3930 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3932 /* Notify of success. */
3933 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3934 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
3935 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3937 /* Unregister the "from" handle. */
3938 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3939 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
3940 * the process isn't completed.
3946 struct nickserv_discrim
{
3947 unsigned int limit
, min_level
, max_level
;
3948 unsigned long flags_on
, flags_off
;
3949 time_t min_registered
, max_registered
;
3951 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3952 const char *nickmask
;
3953 const char *hostmask
;
3954 const char *handlemask
;
3955 const char *emailmask
;
3957 unsigned int inldap
;
3961 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3963 struct discrim_apply_info
{
3964 struct nickserv_discrim
*discrim
;
3965 discrim_search_func func
;
3966 struct userNode
*source
;
3967 unsigned int matched
;
3970 static struct nickserv_discrim
*
3971 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
3974 struct nickserv_discrim
*discrim
;
3976 discrim
= malloc(sizeof(*discrim
));
3977 memset(discrim
, 0, sizeof(*discrim
));
3978 discrim
->min_level
= 0;
3979 discrim
->max_level
= ~0;
3980 discrim
->limit
= 50;
3981 discrim
->min_registered
= 0;
3982 discrim
->max_registered
= INT_MAX
;
3983 discrim
->lastseen
= now
;
3985 discrim
->inldap
= 2;
3988 for (i
=0; i
<argc
; i
++) {
3989 if (i
== argc
- 1) {
3990 reply("MSG_MISSING_PARAMS", argv
[i
]);
3993 if (!irccasecmp(argv
[i
], "limit")) {
3994 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3995 } else if (!irccasecmp(argv
[i
], "flags")) {
3996 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3997 } else if (!irccasecmp(argv
[i
], "registered")) {
3998 const char *cmp
= argv
[++i
];
3999 if (cmp
[0] == '<') {
4000 if (cmp
[1] == '=') {
4001 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
4003 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
4005 } else if (cmp
[0] == '=') {
4006 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
4007 } else if (cmp
[0] == '>') {
4008 if (cmp
[1] == '=') {
4009 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
4011 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
4014 reply("MSG_INVALID_CRITERIA", cmp
);
4016 } else if (!irccasecmp(argv
[i
], "seen")) {
4017 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
4018 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
4019 discrim
->nickmask
= argv
[++i
];
4020 } else if (!irccasecmp(argv
[i
], "hostmask")) {
4022 if (!irccasecmp(argv
[i
], "exact")) {
4023 if (i
== argc
- 1) {
4024 reply("MSG_MISSING_PARAMS", argv
[i
]);
4027 discrim
->hostmask_type
= EXACT
;
4028 } else if (!irccasecmp(argv
[i
], "subset")) {
4029 if (i
== argc
- 1) {
4030 reply("MSG_MISSING_PARAMS", argv
[i
]);
4033 discrim
->hostmask_type
= SUBSET
;
4034 } else if (!irccasecmp(argv
[i
], "superset")) {
4035 if (i
== argc
- 1) {
4036 reply("MSG_MISSING_PARAMS", argv
[i
]);
4039 discrim
->hostmask_type
= SUPERSET
;
4040 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
4041 if (i
== argc
- 1) {
4042 reply("MSG_MISSING_PARAMS", argv
[i
]);
4045 discrim
->hostmask_type
= LASTQUIT
;
4048 discrim
->hostmask_type
= SUPERSET
;
4050 discrim
->hostmask
= argv
[++i
];
4051 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask") || !irccasecmp(argv
[i
], "account")) {
4052 if (!irccasecmp(argv
[++i
], "*")) {
4053 discrim
->handlemask
= 0;
4055 discrim
->handlemask
= argv
[i
];
4057 } else if (!irccasecmp(argv
[i
], "email")) {
4058 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
4059 reply("MSG_NO_SEARCH_ACCESS", "email");
4061 } else if (!irccasecmp(argv
[++i
], "*")) {
4062 discrim
->emailmask
= 0;
4064 discrim
->emailmask
= argv
[i
];
4066 } else if (!irccasecmp(argv
[i
], "access")) {
4067 const char *cmp
= argv
[++i
];
4068 if (cmp
[0] == '<') {
4069 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
4070 if (cmp
[1] == '=') {
4071 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
4073 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
4075 } else if (cmp
[0] == '=') {
4076 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
4077 } else if (cmp
[0] == '>') {
4078 if (cmp
[1] == '=') {
4079 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
4081 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
4084 reply("MSG_INVALID_CRITERIA", cmp
);
4087 } else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[i
], "inldap")) {
4089 if(true_string(argv
[i
])) {
4090 discrim
->inldap
= 1;
4092 else if (false_string(argv
[i
])) {
4093 discrim
->inldap
= 0;
4096 reply("MSG_INVALID_BINARY", argv
[i
]);
4100 reply("MSG_INVALID_CRITERIA", argv
[i
]);
4111 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
4113 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
4114 || (discrim
->flags_off
& hi
->flags
)
4115 || (discrim
->min_registered
> hi
->registered
)
4116 || (discrim
->max_registered
< hi
->registered
)
4117 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
4118 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
4119 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
4120 || (discrim
->min_level
> hi
->opserv_level
)
4121 || (discrim
->max_level
< hi
->opserv_level
)) {
4124 if (discrim
->hostmask
) {
4126 for (i
=0; i
<hi
->masks
->used
; i
++) {
4127 const char *mask
= hi
->masks
->list
[i
];
4128 if ((discrim
->hostmask_type
== SUBSET
)
4129 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
4130 else if ((discrim
->hostmask_type
== EXACT
)
4131 && !irccasecmp(discrim
->hostmask
, mask
)) break;
4132 else if ((discrim
->hostmask_type
== SUPERSET
)
4133 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
4134 else if ((discrim
->hostmask_type
== LASTQUIT
)
4135 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
4137 if (i
==hi
->masks
->used
) return 0;
4139 if (discrim
->nickmask
) {
4140 struct nick_info
*nick
= hi
->nicks
;
4142 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
4145 if (!nick
) return 0;
4148 if(nickserv_conf
.ldap_enable
&& discrim
->inldap
!= 2) {
4150 rc
= ldap_get_user_info(hi
->handle
, NULL
);
4151 if(discrim
->inldap
== 1 && rc
!= LDAP_SUCCESS
)
4153 if(discrim
->inldap
== 0 && rc
== LDAP_SUCCESS
)
4162 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
4164 dict_iterator_t it
, next
;
4165 unsigned int matched
;
4167 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
4168 it
&& (matched
< discrim
->limit
);
4170 next
= iter_next(it
);
4171 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
4172 dsf(source
, iter_data(it
));
4180 search_print_func(struct userNode
*source
, struct handle_info
*match
)
4182 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
4186 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
4191 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
4193 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
4194 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
4198 search_add2ldap_func (struct userNode
*source
, struct handle_info
*match
)
4202 if(match
->email_addr
&& match
->passwd
&& match
->handle
) {
4203 rc
= ldap_do_add(match
->handle
, match
->passwd
, match
->email_addr
);
4204 if(rc
!= LDAP_SUCCESS
) {
4205 send_message(source
, nickserv
, "NSMSG_LDAP_FAIL_ADD", match
->handle
, ldap_err2string(rc
));
4212 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
4214 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
4215 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
4216 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
4217 return hi_b
->opserv_level
- hi_a
->opserv_level
;
4218 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
4222 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
4224 struct handle_info_list hil
;
4225 struct helpfile_table tbl
;
4230 memset(&hil
, 0, sizeof(hil
));
4231 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
4232 struct handle_info
*hi
= iter_data(it
);
4233 if (hi
->opserv_level
)
4234 handle_info_list_append(&hil
, hi
);
4236 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
4237 tbl
.length
= hil
.used
+ 1;
4239 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
4240 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
4241 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4244 for (ii
= 0; ii
< hil
.used
; ) {
4245 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4246 ary
[0] = hil
.list
[ii
]->handle
;
4247 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
4248 tbl
.contents
[++ii
] = ary
;
4250 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4251 /*reply("MSG_MATCH_COUNT", hil.used); */
4252 for (ii
= 0; ii
< hil
.used
; ii
++)
4253 free(tbl
.contents
[ii
]);
4258 static NICKSERV_FUNC(cmd_search
)
4260 struct nickserv_discrim
*discrim
;
4261 discrim_search_func action
;
4262 struct svccmd
*subcmd
;
4263 unsigned int matches
;
4266 NICKSERV_MIN_PARMS(3);
4267 sprintf(buf
, "search %s", argv
[1]);
4268 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
4269 if (!irccasecmp(argv
[1], "print"))
4270 action
= search_print_func
;
4271 else if (!irccasecmp(argv
[1], "count"))
4272 action
= search_count_func
;
4273 else if (!irccasecmp(argv
[1], "unregister"))
4274 action
= search_unregister_func
;
4276 else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[1], "add2ldap"))
4277 action
= search_add2ldap_func
;
4280 reply("NSMSG_INVALID_ACTION", argv
[1]);
4284 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
4287 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
4291 if (action
== search_print_func
)
4292 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4293 else if (action
== search_count_func
)
4294 discrim
->limit
= INT_MAX
;
4296 matches
= nickserv_discrim_search(discrim
, action
, user
);
4299 reply("MSG_MATCH_COUNT", matches
);
4301 reply("MSG_NO_MATCHES");
4307 static MODCMD_FUNC(cmd_checkpass
)
4309 struct handle_info
*hi
;
4311 NICKSERV_MIN_PARMS(3);
4312 if (!(hi
= get_handle_info(argv
[1]))) {
4313 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
4316 if (checkpass(argv
[2], hi
->passwd
))
4317 reply("CHECKPASS_YES");
4319 reply("CHECKPASS_NO");
4325 nickserv_db_read_handle(char *handle
, dict_t obj
)
4328 struct string_list
*masks
, *slist
, *ignores
;
4329 struct handle_info
*hi
;
4330 struct userNode
*authed_users
;
4331 struct userData
*channels
;
4332 unsigned long int id
;
4335 char *setter
, *note
;
4338 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
4339 id
= str
? strtoul(str
, NULL
, 0) : 0;
4340 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
4342 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
4345 if ((hi
= get_handle_info(handle
))) {
4346 authed_users
= hi
->users
;
4347 channels
= hi
->channels
;
4349 hi
->channels
= NULL
;
4350 dict_remove(nickserv_handle_dict
, hi
->handle
);
4352 authed_users
= NULL
;
4355 if(nickserv_conf
.force_handles_lowercase
)
4356 irc_strtolower(handle
);
4357 hi
= register_handle(handle
, str
, id
);
4359 hi
->users
= authed_users
;
4360 while (authed_users
) {
4361 authed_users
->handle_info
= hi
;
4362 authed_users
= authed_users
->next_authed
;
4365 hi
->channels
= channels
;
4366 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
4367 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
4368 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
4369 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
4370 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
4371 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
4372 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
4373 hi
->language
= language_find(str
? str
: "C");
4374 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
4375 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
4376 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
4378 hi
->infoline
= strdup(str
);
4379 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
4380 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4381 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
4382 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
4383 /* We want to read the nicks even if disable_nicks is set. This is so
4384 * that we don't lose the nick data entirely. */
4385 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
4387 for (ii
=0; ii
<slist
->used
; ii
++)
4388 register_nick(slist
->list
[ii
], hi
);
4390 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
4392 for (ii
=0; str
[ii
]; ii
++)
4393 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
4395 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
4396 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4397 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
4398 hi
->announcements
= str
? str
[0] : '?';
4399 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
4400 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
4401 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
4402 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
4403 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
4405 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
4407 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
4408 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
4410 nickserv_set_email_addr(hi
, str
);
4411 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
4413 hi
->epithet
= strdup(str
);
4414 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
4416 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
4417 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
4418 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4419 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
4420 if (setter
&& date
&& note
)
4422 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
4427 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
4429 hi
->fakehost
= strdup(str
);
4431 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4433 const char *data
, *type
, *expires
, *cookie_str
;
4434 struct handle_cookie
*cookie
;
4436 cookie
= calloc(1, sizeof(*cookie
));
4437 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4438 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4439 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4440 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4441 if (!type
|| !expires
|| !cookie_str
) {
4442 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4445 if (!irccasecmp(type
, KEY_ACTIVATION
))
4446 cookie
->type
= ACTIVATION
;
4447 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4448 cookie
->type
= PASSWORD_CHANGE
;
4449 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4450 cookie
->type
= EMAIL_CHANGE
;
4451 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4452 cookie
->type
= ALLOWAUTH
;
4454 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4457 cookie
->expires
= strtoul(expires
, NULL
, 0);
4458 if (cookie
->expires
< now
)
4461 cookie
->data
= strdup(data
);
4462 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4466 nickserv_bake_cookie(cookie
);
4468 nickserv_free_cookie(cookie
);
4473 nickserv_saxdb_read(dict_t db
) {
4475 struct record_data
*rd
;
4478 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4480 handle
= strdup(iter_key(it
));
4481 nickserv_db_read_handle(handle
, rd
->d
.object
);
4487 static NICKSERV_FUNC(cmd_mergedb
)
4489 struct timeval start
, stop
;
4492 NICKSERV_MIN_PARMS(2);
4493 gettimeofday(&start
, NULL
);
4494 if (!(db
= parse_database(argv
[1]))) {
4495 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4498 nickserv_saxdb_read(db
);
4500 gettimeofday(&stop
, NULL
);
4501 stop
.tv_sec
-= start
.tv_sec
;
4502 stop
.tv_usec
-= start
.tv_usec
;
4503 if (stop
.tv_usec
< 0) {
4505 stop
.tv_usec
+= 1000000;
4507 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4512 expire_handles(UNUSED_ARG(void *data
))
4514 dict_iterator_t it
, next
;
4516 struct handle_info
*hi
;
4518 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4519 next
= iter_next(it
);
4521 if ((hi
->opserv_level
> 0)
4523 || HANDLE_FLAGGED(hi
, FROZEN
)
4524 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4527 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4528 if ((now
- hi
->lastseen
) > expiry
) {
4529 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4530 nickserv_unregister_handle(hi
, NULL
, NULL
);
4534 if (nickserv_conf
.handle_expire_frequency
)
4535 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4539 nickserv_load_dict(const char *fname
)
4543 if (!(file
= fopen(fname
, "r"))) {
4544 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4547 while (!feof(file
)) {
4548 fgets(line
, sizeof(line
), file
);
4551 if (line
[strlen(line
)-1] == '\n')
4552 line
[strlen(line
)-1] = 0;
4553 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4556 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4559 static enum reclaim_action
4560 reclaim_action_from_string(const char *str
) {
4562 return RECLAIM_NONE
;
4563 else if (!irccasecmp(str
, "warn"))
4564 return RECLAIM_WARN
;
4565 else if (!irccasecmp(str
, "svsnick"))
4566 return RECLAIM_SVSNICK
;
4567 else if (!irccasecmp(str
, "kill"))
4568 return RECLAIM_KILL
;
4570 return RECLAIM_NONE
;
4574 nickserv_conf_read(void)
4576 dict_t conf_node
, child
;
4579 struct string_list
*strlist
;
4581 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4582 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4585 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4587 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4588 if (nickserv_conf
.valid_handle_regex_set
)
4589 regfree(&nickserv_conf
.valid_handle_regex
);
4591 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4592 nickserv_conf
.valid_handle_regex_set
= !err
;
4593 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4595 nickserv_conf
.valid_handle_regex_set
= 0;
4597 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4598 if (nickserv_conf
.valid_nick_regex_set
)
4599 regfree(&nickserv_conf
.valid_nick_regex
);
4601 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4602 nickserv_conf
.valid_nick_regex_set
= !err
;
4603 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4605 nickserv_conf
.valid_nick_regex_set
= 0;
4607 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4608 if (nickserv_conf
.valid_fakehost_regex_set
)
4609 regfree(&nickserv_conf
.valid_fakehost_regex
);
4611 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4612 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4613 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4615 nickserv_conf
.valid_fakehost_regex_set
= 0;
4617 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4619 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4620 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4621 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4622 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4623 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4624 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4625 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4626 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4627 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4628 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4629 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4630 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4631 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4632 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4633 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4634 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4635 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4636 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4637 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4638 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4639 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4640 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4641 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4642 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4643 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4645 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4646 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4647 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4649 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4650 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4651 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4653 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4654 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4655 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4656 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4657 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4658 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4659 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4660 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4661 if (!nickserv_conf
.disable_nicks
) {
4662 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4663 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4664 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4665 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4666 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4667 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4668 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4669 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4671 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4672 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4673 const char *key
= iter_key(it
), *value
;
4677 if (!strncasecmp(key
, "uc_", 3))
4678 flag
= toupper(key
[3]);
4679 else if (!strncasecmp(key
, "lc_", 3))
4680 flag
= tolower(key
[3]);
4684 if ((pos
= handle_inverse_flags
[flag
])) {
4685 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4686 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4689 if (nickserv_conf
.weak_password_dict
)
4690 dict_delete(nickserv_conf
.weak_password_dict
);
4691 nickserv_conf
.weak_password_dict
= dict_new();
4692 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4693 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4694 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4695 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4697 nickserv_load_dict(str
);
4698 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4699 if (nickserv
&& str
)
4700 NickChange(nickserv
, str
, 0);
4701 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4702 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4703 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4704 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4705 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4706 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4707 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4708 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4709 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4710 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4711 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4712 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4713 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4714 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4715 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4716 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4717 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4718 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4719 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4720 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4722 free_string_list(nickserv_conf
.denied_fakehost_words
);
4723 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4725 strlist
= string_list_copy(strlist
);
4727 strlist
= alloc_string_list(4);
4728 string_list_append(strlist
, strdup("sex"));
4729 string_list_append(strlist
, strdup("fuck"));
4731 nickserv_conf
.denied_fakehost_words
= strlist
;
4733 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4734 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4736 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4737 nickserv_conf
.auto_oper
= str
? str
: "";
4739 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4740 nickserv_conf
.auto_admin
= str
? str
: "";
4742 str
= conf_get_data("server/network", RECDB_QSTRING
);
4743 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4744 if (!nickserv_conf
.auth_policer_params
) {
4745 nickserv_conf
.auth_policer_params
= policer_params_new();
4746 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4747 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4749 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4750 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4751 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4753 str
= database_get_data(conf_node
, KEY_LDAP_ENABLE
, RECDB_QSTRING
);
4754 nickserv_conf
.ldap_enable
= str
? strtoul(str
, NULL
, 0) : 0;
4756 str
= database_get_data(conf_node
, KEY_FORCE_HANDLES_LOWERCASE
, RECDB_QSTRING
);
4757 nickserv_conf
.force_handles_lowercase
= str
? strtol(str
, NULL
, 0) : 0;
4760 if(nickserv_conf
.ldap_enable
> 0) {
4761 /* ldap is enabled but not compiled in - error out */
4762 log_module(MAIN_LOG
, LOG_ERROR
, "ldap is enabled in config, but not compiled in!");
4763 nickserv_conf
.ldap_enable
= 0;
4769 str
= database_get_data(conf_node
, KEY_LDAP_URI
, RECDB_QSTRING
);
4770 nickserv_conf
.ldap_uri
= str
? str
: "";
4772 str
= database_get_data(conf_node
, KEY_LDAP_BASE
, RECDB_QSTRING
);
4773 nickserv_conf
.ldap_base
= str
? str
: "";
4775 str
= database_get_data(conf_node
, KEY_LDAP_DN_FMT
, RECDB_QSTRING
);
4776 nickserv_conf
.ldap_dn_fmt
= str
? str
: "";
4778 str
= database_get_data(conf_node
, KEY_LDAP_VERSION
, RECDB_QSTRING
);
4779 nickserv_conf
.ldap_version
= str
? strtoul(str
, NULL
, 0) : 3;
4781 str
= database_get_data(conf_node
, KEY_LDAP_AUTOCREATE
, RECDB_QSTRING
);
4782 nickserv_conf
.ldap_autocreate
= str
? strtoul(str
, NULL
, 0) : 0;
4784 str
= database_get_data(conf_node
, KEY_LDAP_TIMEOUT
, RECDB_QSTRING
);
4785 nickserv_conf
.ldap_timeout
= str
? strtoul(str
, NULL
, 0) : 5;
4787 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_DN
, RECDB_QSTRING
);
4788 nickserv_conf
.ldap_admin_dn
= str
? str
: "";
4790 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_PASS
, RECDB_QSTRING
);
4791 nickserv_conf
.ldap_admin_pass
= str
? str
: "";
4793 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_ACCOUNT
, RECDB_QSTRING
);
4794 nickserv_conf
.ldap_field_account
= str
? str
: "";
4796 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_PASSWORD
, RECDB_QSTRING
);
4797 nickserv_conf
.ldap_field_password
= str
? str
: "";
4799 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_EMAIL
, RECDB_QSTRING
);
4800 nickserv_conf
.ldap_field_email
= str
? str
: "";
4802 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_DN
, RECDB_QSTRING
);
4803 nickserv_conf
.ldap_oper_group_dn
= str
? str
: "";
4805 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_LEVEL
, RECDB_QSTRING
);
4806 nickserv_conf
.ldap_oper_group_level
= str
? strtoul(str
, NULL
, 0) : 99;
4808 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_GROUP_MEMBER
, RECDB_QSTRING
);
4809 nickserv_conf
.ldap_field_group_member
= str
? str
: "";
4811 free_string_list(nickserv_conf
.ldap_object_classes
);
4812 strlist
= database_get_data(conf_node
, KEY_LDAP_OBJECT_CLASSES
, RECDB_STRING_LIST
);
4814 strlist
= string_list_copy(strlist
);
4816 strlist
= alloc_string_list(4);
4817 string_list_append(strlist
, strdup("top"));
4819 nickserv_conf
.ldap_object_classes
= strlist
;
4826 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4828 char newnick
[NICKLEN
+1];
4837 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4839 case RECLAIM_SVSNICK
:
4841 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4842 } while (GetUserH(newnick
));
4843 irc_svsnick(nickserv
, user
, newnick
);
4846 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4847 irc_kill(nickserv
, user
, msg
);
4853 nickserv_reclaim_p(void *data
) {
4854 struct userNode
*user
= data
;
4855 struct nick_info
*ni
= get_nick_info(user
->nick
);
4857 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4861 check_user_nick(struct userNode
*user
) {
4862 struct nick_info
*ni
;
4863 user
->modes
&= ~FLAGS_REGNICK
;
4864 if (!(ni
= get_nick_info(user
->nick
)))
4866 if (user
->handle_info
== ni
->owner
) {
4867 user
->modes
|= FLAGS_REGNICK
;
4871 if (nickserv_conf
.warn_nick_owned
)
4872 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4873 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4875 if (nickserv_conf
.auto_reclaim_delay
)
4876 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4878 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4883 handle_new_user(struct userNode
*user
)
4885 return check_user_nick(user
);
4889 handle_account(struct userNode
*user
, const char *stamp
)
4891 struct handle_info
*hi
;
4894 #ifdef WITH_PROTOCOL_P10
4895 time_t timestamp
= 0;
4897 colon
= strchr(stamp
, ':');
4898 if(colon
&& colon
[1])
4901 timestamp
= atoi(colon
+1);
4903 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4904 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4906 log_module(MAIN_LOG
, LOG_WARNING
, "%s using account %s but timestamp does not match %lu is not %lu.", user
->nick
, stamp
, timestamp
, hi
->registered
);
4910 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4911 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4915 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4918 set_user_handle_info(user
, hi
, 0);
4920 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4925 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4927 struct handle_info
*hi
;
4929 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4930 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4931 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4933 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4934 check_user_nick(user
);
4938 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4940 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4941 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4942 set_user_handle_info(user
, NULL
, 0);
4945 static struct modcmd
*
4946 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4948 if (min_level
> 0) {
4950 sprintf(buf
, "%u", min_level
);
4951 if (must_be_qualified
) {
4952 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4954 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4956 } else if (min_level
== 0) {
4957 if (must_be_qualified
) {
4958 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4960 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4963 if (must_be_qualified
) {
4964 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4966 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4972 nickserv_db_cleanup(void)
4974 unreg_del_user_func(nickserv_remove_user
);
4975 userList_clean(&curr_helpers
);
4976 policer_params_delete(nickserv_conf
.auth_policer_params
);
4977 dict_delete(nickserv_handle_dict
);
4978 dict_delete(nickserv_nick_dict
);
4979 dict_delete(nickserv_opt_dict
);
4980 dict_delete(nickserv_allow_auth_dict
);
4981 dict_delete(nickserv_email_dict
);
4982 dict_delete(nickserv_id_dict
);
4983 dict_delete(nickserv_conf
.weak_password_dict
);
4984 free(auth_func_list
);
4985 free(unreg_func_list
);
4987 free(allowauth_func_list
);
4988 free(handle_merge_func_list
);
4989 free(failpw_func_list
);
4990 if (nickserv_conf
.valid_handle_regex_set
)
4991 regfree(&nickserv_conf
.valid_handle_regex
);
4992 if (nickserv_conf
.valid_nick_regex_set
)
4993 regfree(&nickserv_conf
.valid_nick_regex
);
4997 init_nickserv(const char *nick
)
4999 struct chanNode
*chan
;
5001 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
5002 reg_new_user_func(handle_new_user
);
5003 reg_nick_change_func(handle_nick_change
);
5004 reg_del_user_func(nickserv_remove_user
);
5005 reg_account_func(handle_account
);
5007 /* set up handle_inverse_flags */
5008 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
5009 for (i
=0; handle_flags
[i
]; i
++) {
5010 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
5011 flag_access_levels
[i
] = 0;
5014 conf_register_reload(nickserv_conf_read
);
5015 nickserv_opt_dict
= dict_new();
5016 nickserv_email_dict
= dict_new();
5018 dict_set_free_keys(nickserv_email_dict
, free
);
5019 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
5021 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
5022 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
5023 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
5024 * a big pain to disable since its nolonger in the config file. ) -Rubin
5026 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
5027 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
5028 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
5029 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
5030 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
5031 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
5032 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
5033 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
5034 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
5035 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
5036 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
5037 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
5038 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
5039 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
5040 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
5041 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
5042 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
5043 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
5044 if (!nickserv_conf
.disable_nicks
) {
5045 /* nick management commands */
5046 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
5047 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
5048 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
5049 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
5050 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
5051 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
5053 if (nickserv_conf
.email_enabled
) {
5054 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
5055 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
5056 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
5057 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
5058 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
5059 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
5061 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
5062 /* ignore commands */
5063 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
5064 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
5065 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
5066 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
5067 /* miscellaneous commands */
5068 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
5069 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
5070 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
5071 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
5072 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
5074 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
5075 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
5076 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
5077 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
5078 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
5079 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
5080 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
5081 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
5082 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
5083 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
5084 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
5085 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
5086 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
5087 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
5088 if (nickserv_conf
.titlehost_suffix
) {
5089 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
5090 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
5092 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
5093 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
5094 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
5095 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
5097 nickserv_handle_dict
= dict_new();
5098 dict_set_free_keys(nickserv_handle_dict
, free
);
5099 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
5101 nickserv_id_dict
= dict_new();
5102 dict_set_free_keys(nickserv_id_dict
, free
);
5104 nickserv_nick_dict
= dict_new();
5105 dict_set_free_data(nickserv_nick_dict
, free
);
5107 nickserv_allow_auth_dict
= dict_new();
5109 userList_init(&curr_helpers
);
5112 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
5113 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
5114 nickserv_service
= service_register(nickserv
);
5116 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
5117 reg_exit_func(nickserv_db_cleanup
);
5118 if(nickserv_conf
.handle_expire_frequency
)
5119 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
5121 if(autojoin_channels
&& nickserv
) {
5122 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
5123 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
5124 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
5128 ldap_do_init(nickserv_conf
);
5131 message_register_table(msgtab
);