1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
32 #include <tre/regex.h>
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_FIELD_GROUP_MEMBER "ldap_field_group_member"
132 #define KEY_LDAP_TIMEOUT "ldap_timeout"
135 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
137 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
138 #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[])
139 typedef OPTION_FUNC(option_func_t
);
141 DEFINE_LIST(handle_info_list
, struct handle_info
*);
143 #define NICKSERV_MIN_PARMS(N) do { \
145 reply("MSG_MISSING_PARAMS", argv[0]); \
146 svccmd_send_help_brief(user, nickserv, cmd); \
150 struct userNode
*nickserv
;
151 struct userList curr_helpers
;
152 const char *handle_flags
= HANDLE_FLAGS
;
154 extern struct string_list
*autojoin_channels
;
155 static struct module *nickserv_module
;
156 static struct service
*nickserv_service
;
157 static struct log_type
*NS_LOG
;
158 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
159 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
160 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
161 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
162 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
163 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
164 static char handle_inverse_flags
[256];
165 static unsigned int flag_access_levels
[32];
166 static const struct message_entry msgtab
[] = {
167 { "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." },
168 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
169 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu characters or less."},
170 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
171 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
172 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
173 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
174 { "NSMSG_LDAP_FAIL", "There was a problem in contacting the account server (ldap): %s. Please try again later." },
175 { "NSMSG_LDAP_FAIL_ADD", "There was a problem in adding account %s to ldap: %s." },
176 { "NSMSG_LDAP_FAIL_SEND_EMAIL", "There was a problem in storing your email address in the account server (ldap): %s. Please try again later." },
177 { "NSMSG_LDAP_FAIL_GET_EMAIL", "There was a problem in retrieving your email address from the account server (ldap): %s. Please try again later." },
178 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
179 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
180 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
181 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
182 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
183 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
184 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
185 { "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." },
186 { "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." },
187 { "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." },
188 { "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." },
189 { "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." },
190 { "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." },
191 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
192 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
193 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
194 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
195 { "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." },
196 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
197 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
198 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
199 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
200 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
201 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
202 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
203 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
204 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
205 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
206 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
207 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
208 { "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 *@*)." },
209 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
210 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
211 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
212 { "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)" },
213 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
214 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
215 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
216 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
217 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
218 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
219 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
220 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
221 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
222 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
223 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
224 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
225 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
226 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
227 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
228 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
229 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
230 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
231 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
232 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
233 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
234 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
235 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
236 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
237 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
238 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
239 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
240 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
241 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
242 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
243 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
244 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
245 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
246 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
247 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
248 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
249 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
250 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
251 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
252 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
253 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
254 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
255 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
256 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
257 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
258 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
259 { "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)." },
260 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
261 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
262 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
263 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
264 { "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." },
265 { "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." },
266 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
267 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
268 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
269 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
270 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
271 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
272 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
273 { "NSMSG_PASS_SUCCESS", "Password changed." },
274 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
275 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
276 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
277 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
278 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
279 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
280 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
281 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
282 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
283 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
284 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
285 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
286 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
287 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
288 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
289 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
290 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
291 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
292 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
293 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
294 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
295 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
296 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
297 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
298 { "NSMSG_NO_ACCESS", "Access denied." },
299 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
300 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
301 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
302 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
303 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
304 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
305 { "NSMSG_BAD_HANDLE", "Account $b%s$b is not allowed because it is reserved, is too long, or contains invalid characters." },
306 { "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." },
307 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
308 { "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." },
309 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
310 { "NSMSG_SEARCH_MATCH", "Match: %s" },
311 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
312 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
313 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
314 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
315 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
316 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
317 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
318 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
319 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
320 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
321 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
322 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
323 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
324 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
325 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
326 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
327 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
328 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
329 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
330 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
331 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
332 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
333 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
334 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
335 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
336 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
337 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
338 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
339 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
340 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
341 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
342 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
343 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
344 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
346 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
347 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
349 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
350 { "NSEMAIL_ACTIVATION_BODY",
351 "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"
353 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
354 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
355 "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"
356 "/msg %3$s@%4$s AUTH %5$s your-password\n"
357 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
358 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
360 "If you did NOT request this account, you do not need to do anything.\n"
361 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
362 { "NSEMAIL_ACTIVATION_BODY_WEB",
363 "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"
365 "To verify your email address and complete the account registration, visit the following URL:\n"
366 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
368 "If you did NOT request this account, you do not need to do anything.\n"
369 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
370 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
371 { "NSEMAIL_PASSWORD_CHANGE_BODY",
372 "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"
373 "To complete the password change, log on to %1$s and type the following command:\n"
374 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
375 "If you did NOT request your password to be changed, you do not need to do anything.\n"
376 "Please contact the %1$s staff if you have questions." },
377 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
378 "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"
379 "To complete the password change, click the following URL:\n"
380 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
381 "If you did NOT request your password to be changed, you do not need to do anything.\n"
382 "Please contact the %1$s staff if you have questions." },
383 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
384 #ifdef stupid_verify_old_email
385 { "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." },
386 { "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." },
388 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
389 { "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." },
390 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
391 { "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." },
392 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
393 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
394 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
395 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
396 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
397 { "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." },
398 { "CHECKPASS_YES", "Yes." },
399 { "CHECKPASS_NO", "No." },
400 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
404 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
405 static void nickserv_reclaim_p(void *data
);
407 struct nickserv_config nickserv_conf
;
409 /* We have 2^32 unique account IDs to use. */
410 unsigned long int highest_id
= 0;
413 canonicalize_hostmask(char *mask
)
415 char *out
= mask
, *temp
;
416 if ((temp
= strchr(mask
, '!'))) {
418 while (*temp
) *out
++ = *temp
++;
424 static struct handle_note
*
425 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
427 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
429 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
431 memcpy(note
->note
, text
, strlen(text
));
435 static struct handle_info
*
436 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
438 struct handle_info
*hi
;
440 hi
= calloc(1, sizeof(*hi
));
441 hi
->userlist_style
= nickserv_conf
.default_style
? nickserv_conf
.default_style
: HI_DEFAULT_STYLE
;
442 hi
->announcements
= '?';
443 hi
->handle
= strdup(handle
);
444 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
446 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
452 register_nick(const char *nick
, struct handle_info
*owner
)
454 struct nick_info
*ni
;
455 ni
= malloc(sizeof(struct nick_info
));
456 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
458 ni
->next
= owner
->nicks
;
460 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
464 delete_nick(struct nick_info
*ni
)
466 struct nick_info
*last
, *next
;
467 struct userNode
*user
;
468 /* Check to see if we should mark a user as unregistered. */
469 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
470 user
->modes
&= ~FLAGS_REGNICK
;
473 /* Remove ni from the nick_info linked list. */
474 if (ni
== ni
->owner
->nicks
) {
475 ni
->owner
->nicks
= ni
->next
;
477 last
= ni
->owner
->nicks
;
483 last
->next
= next
->next
;
485 dict_remove(nickserv_nick_dict
, ni
->nick
);
488 static unreg_func_t
*unreg_func_list
;
489 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
492 reg_unreg_func(unreg_func_t func
)
494 if (unreg_func_used
== unreg_func_size
) {
495 if (unreg_func_size
) {
496 unreg_func_size
<<= 1;
497 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
500 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
503 unreg_func_list
[unreg_func_used
++] = func
;
507 nickserv_free_cookie(void *data
)
509 struct handle_cookie
*cookie
= data
;
510 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
511 if (cookie
->data
) free(cookie
->data
);
516 free_handle_info(void *vhi
)
518 struct handle_info
*hi
= vhi
;
520 free_string_list(hi
->masks
);
521 free_string_list(hi
->ignores
);
525 delete_nick(hi
->nicks
);
531 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
532 nickserv_free_cookie(hi
->cookie
);
534 if (hi
->email_addr
) {
535 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
536 handle_info_list_remove(hil
, hi
);
538 dict_remove(nickserv_email_dict
, hi
->email_addr
);
543 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
546 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
549 struct userNode
*uNode
;
552 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
554 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
555 if( (rc
= ldap_delete_account(hi
->handle
)) != LDAP_SUCCESS
) {
557 send_message(notify
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
559 if(rc
!= LDAP_NO_SUCH_OBJECT
)
560 return false; /* if theres noone there to delete, its kinda ok, right ?:) */
565 for (n
=0; n
<unreg_func_used
; n
++)
566 unreg_func_list
[n
](notify
, hi
);
568 if (nickserv_conf
.sync_log
) {
569 uNode
= GetUserH(hi
->users
->nick
);
573 set_user_handle_info(hi
->users
, NULL
, 0);
576 if (nickserv_conf
.disable_nicks
)
577 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
579 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
582 if (nickserv_conf
.sync_log
)
583 SyncLog("UNREGISTER %s", hi
->handle
);
585 dict_remove(nickserv_handle_dict
, hi
->handle
);
590 get_handle_info(const char *handle
)
592 return dict_find(nickserv_handle_dict
, handle
, 0);
596 get_nick_info(const char *nick
)
598 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
602 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
607 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
608 mn
= channel
->members
.list
[nn
];
609 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
616 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
617 if (!user
->handle_info
) {
619 send_message(user
, bot
, "MSG_AUTHENTICATE");
623 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
625 send_message(user
, bot
, "NSMSG_NO_ACCESS");
629 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
631 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
635 if (user
->handle_info
->opserv_level
< min_level
) {
637 send_message(user
, bot
, "NSMSG_NO_ACCESS");
645 is_valid_handle(const char *handle
)
647 struct userNode
*user
;
648 /* cant register a juped nick/service nick as handle, to prevent confusion */
649 user
= GetUserH(handle
);
650 if (user
&& IsLocal(user
))
652 /* check against maximum length */
653 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
655 /* for consistency, only allow account names that could be nicks */
656 if (!is_valid_nick(handle
))
658 /* disallow account names that look like bad words */
659 if (opserv_bad_channel(handle
))
661 /* test either regex or containing all valid chars */
662 if (nickserv_conf
.valid_handle_regex_set
) {
663 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
666 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
667 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
671 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
676 is_registerable_nick(const char *nick
)
678 struct userNode
*user
;
679 /* cant register a juped nick/service nick as nick, to prevent confusion */
680 user
= GetUserH(nick
);
681 if (user
&& IsLocal(user
))
683 /* for consistency, only allow nicks names that could be nicks */
684 if (!is_valid_nick(nick
))
686 /* disallow nicks that look like bad words */
687 if (opserv_bad_channel(nick
))
690 if (strlen(nick
) > NICKLEN
)
692 /* test either regex or as valid handle */
693 if (nickserv_conf
.valid_nick_regex_set
) {
694 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
697 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
698 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
704 /* this has been replaced with one in tools.c
707 is_valid_email_addr(const char *email)
709 return strchr(email, '@') != NULL;
715 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
717 if (hi
->email_addr
) {
718 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
719 return hi
->email_addr
;
729 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
731 struct handle_info
*hi
;
732 struct userNode
*target
;
736 if (!(hi
= get_handle_info(++name
))) {
737 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
742 if (!(target
= GetUserH(name
))) {
743 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
746 if (IsLocal(target
)) {
747 if (IsService(target
))
748 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
750 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
753 if (!(hi
= target
->handle_info
)) {
754 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
762 oper_outranks(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
) {
763 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
765 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
766 if ((user
->handle_info
->opserv_level
== 1000)
767 || (user
->handle_info
== hi
)
768 || ((user
->handle_info
->opserv_level
== 0)
769 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
770 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
774 reply("MSG_USER_OUTRANKED", hi
->handle
);
779 get_victim_oper(struct svccmd
*cmd
, struct userNode
*user
, const char *target
)
781 struct handle_info
*hi
;
782 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
784 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
785 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
788 return oper_outranks(cmd
, user
, hi
) ? hi
: NULL
;
792 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
796 /* If no hostmasks on the account, allow it. */
797 if (!hi
->masks
->used
)
799 /* If any hostmask matches, allow it. */
800 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
801 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
803 /* If they are allowauthed to this account, allow it (removing the aa). */
804 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
805 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
808 /* The user is not allowed to use this account. */
813 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
816 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
820 if (len
< nickserv_conf
.password_min_length
) {
822 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
825 if (!irccasecmp(pass
, handle
)) {
827 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
830 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
833 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
836 for (i
=0; i
<len
; i
++) {
837 if (isdigit(pass
[i
]))
839 if (isupper(pass
[i
]))
841 if (islower(pass
[i
]))
844 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
845 || (cnt_upper
< nickserv_conf
.password_min_upper
)
846 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
848 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
854 static auth_func_t
*auth_func_list
;
855 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
858 reg_auth_func(auth_func_t func
)
860 if (auth_func_used
== auth_func_size
) {
861 if (auth_func_size
) {
862 auth_func_size
<<= 1;
863 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
866 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
869 auth_func_list
[auth_func_used
++] = func
;
872 static handle_rename_func_t
*rf_list
;
873 static unsigned int rf_list_size
, rf_list_used
;
876 reg_handle_rename_func(handle_rename_func_t func
)
878 if (rf_list_used
== rf_list_size
) {
881 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
884 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
887 rf_list
[rf_list_used
++] = func
;
891 generate_fakehost(struct handle_info
*handle
)
893 struct userNode
*target
;
894 extern const char *hidden_host_suffix
;
895 static char buffer
[HOSTLEN
+1];
899 if (!handle
->fakehost
) {
900 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
905 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
906 else if (style
== 2) {
907 /* Due to the way fakehost is coded theres no way i can
908 get the exact user, so for now ill just take the first
910 for (target
= handle
->users
; target
; target
= target
->next_authed
)
913 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
916 } else if (handle
->fakehost
[0] == '.') {
917 /* A leading dot indicates the stored value is actually a title. */
918 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
921 return handle
->fakehost
;
925 apply_fakehost(struct handle_info
*handle
)
927 struct userNode
*target
;
932 fake
= generate_fakehost(handle
);
933 for (target
= handle
->users
; target
; target
= target
->next_authed
)
934 assign_fakehost(target
, fake
, 1);
937 void send_func_list(struct userNode
*user
)
940 struct handle_info
*old_info
;
942 old_info
= user
->handle_info
;
944 for (n
=0; n
<auth_func_used
; n
++)
945 auth_func_list
[n
](user
, old_info
);
949 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
952 struct handle_info
*old_info
;
954 /* This can happen if somebody uses COOKIE while authed, or if
955 * they re-auth to their current handle (which is silly, but users
957 if (user
->handle_info
== hi
)
960 if (user
->handle_info
) {
961 struct userNode
*other
;
964 userList_remove(&curr_helpers
, user
);
966 /* remove from next_authed linked list */
967 if (user
->handle_info
->users
== user
) {
968 user
->handle_info
->users
= user
->next_authed
;
970 for (other
= user
->handle_info
->users
;
971 other
->next_authed
!= user
;
972 other
= other
->next_authed
) ;
973 other
->next_authed
= user
->next_authed
;
975 /* if nobody left on old handle, and they're not an oper, remove !god */
976 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
977 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
978 /* record them as being last seen at this time */
979 user
->handle_info
->lastseen
= now
;
980 /* and record their hostmask */
981 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
983 old_info
= user
->handle_info
;
984 user
->handle_info
= hi
;
985 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
986 HANDLE_CLEAR_FLAG(hi
, HELPING
);
988 /* Call auth handlers */
989 if (!GetUserH(user
->nick
))
993 struct nick_info
*ni
;
995 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
996 if (nickserv_conf
.warn_clone_auth
) {
997 struct userNode
*other
;
998 for (other
= hi
->users
; other
; other
= other
->next_authed
)
999 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1002 /* Add this auth to users list of current auths */
1003 user
->next_authed
= hi
->users
;
1006 /* Add to helpers list */
1008 userList_append(&curr_helpers
, user
);
1010 /* Set the fakehost */
1011 if (hi
->fakehost
|| old_info
)
1015 #ifdef WITH_PROTOCOL_P10
1016 /* Stamp users with their account name. */
1017 char *id
= hi
->handle
;
1019 const char *id
= "???";
1021 /* Mark all the nicks registered to this
1022 * account as registered nicks
1023 * - Why not just this one? -rubin */
1024 if (!nickserv_conf
.disable_nicks
) {
1025 struct nick_info
*ni
;
1026 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1027 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1028 user
->modes
|= FLAGS_REGNICK
;
1033 /* send the account to the ircd */
1034 StampUser(user
, id
, hi
->registered
);
1037 /* Stop trying to kick this user off their nick */
1038 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1039 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1041 /* We cannot clear the user's account ID, unfortunately. */
1042 user
->next_authed
= NULL
;
1045 /* Call auth handlers */
1046 if (GetUserH(user
->nick
)) {
1047 for (n
=0; n
<auth_func_used
; n
++)
1048 auth_func_list
[n
](user
, old_info
);
1052 static struct handle_info
*
1053 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1055 struct handle_info
*hi
;
1056 struct nick_info
*ni
;
1057 char crypted
[MD5_CRYPT_LENGTH
];
1059 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1061 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1065 if(strlen(handle
) > 15)
1068 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1072 if (!is_secure_password(handle
, passwd
, user
))
1075 cryptpass(passwd
, crypted
);
1077 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1079 rc
= ldap_do_add(handle
, crypted
, NULL
);
1080 if(LDAP_SUCCESS
!= rc
&& LDAP_ALREADY_EXISTS
!= rc
) {
1082 send_message(user
, nickserv
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1087 hi
= register_handle(handle
, crypted
, 0);
1088 hi
->masks
= alloc_string_list(1);
1089 hi
->ignores
= alloc_string_list(1);
1091 hi
->language
= lang_C
;
1092 hi
->registered
= now
;
1094 hi
->flags
= HI_DEFAULT_FLAGS
;
1095 if (settee
&& !no_auth
)
1096 set_user_handle_info(settee
, hi
, 1);
1098 if (user
!= settee
) {
1100 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1102 else if (nickserv_conf
.disable_nicks
) {
1104 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1107 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
))) {
1109 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1114 register_nick(user
->nick
, hi
);
1115 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1118 if (settee
&& (user
!= settee
)) {
1120 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1127 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1129 cookie
->hi
->cookie
= cookie
;
1130 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1133 /* Contributed by the great sneep of afternet ;) */
1134 /* Since this gets used in a URL, we want to avoid stuff that confuses
1135 * email clients such as ] and ?. a-z, 0-9 only.
1137 void genpass(char *str
, int len
)
1142 for(i
= 0; i
< len
; i
++)
1146 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1147 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1155 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1157 struct handle_cookie
*cookie
;
1158 char subject
[128], body
[4096], *misc
;
1159 const char *netname
, *fmt
;
1163 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1167 cookie
= calloc(1, sizeof(*cookie
));
1169 cookie
->type
= type
;
1170 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1172 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1173 /* Adding dedicated password gen function for more control -Rubin */
1174 genpass(cookie
->cookie
, 10);
1176 *inttobase64(cookie->cookie, rand(), 5);
1177 *inttobase64(cookie->cookie+5, rand(), 5);
1180 netname
= nickserv_conf
.network_name
;
1183 switch (cookie
->type
) {
1185 hi
->passwd
[0] = 0; /* invalidate password */
1186 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1187 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1188 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1191 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1193 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1195 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1198 case PASSWORD_CHANGE
:
1199 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1200 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1201 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1203 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1205 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1206 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1209 misc
= hi
->email_addr
;
1210 hi
->email_addr
= cookie
->data
;
1211 #ifdef stupid_verify_old_email
1213 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1214 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1215 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1216 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1217 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1218 sendmail(nickserv
, hi
, subject
, body
, 1);
1219 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1220 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1223 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1224 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1225 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1226 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1227 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1228 sendmail(nickserv
, hi
, subject
, body
, 1);
1230 #ifdef stupid_verify_old_email
1233 hi
->email_addr
= misc
;
1236 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1237 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1238 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1239 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1240 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1243 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1247 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1248 nickserv_bake_cookie(cookie
);
1252 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1254 cookie
->hi
->cookie
= NULL
;
1255 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1256 nickserv_free_cookie(cookie
);
1260 nickserv_free_email_addr(void *data
)
1262 handle_info_list_clean(data
);
1267 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1269 struct handle_info_list
*hil
;
1270 /* Remove from old handle_info_list ... */
1271 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1272 handle_info_list_remove(hil
, hi
);
1273 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1274 hi
->email_addr
= NULL
;
1276 /* Add to the new list.. */
1277 if (new_email_addr
) {
1278 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1279 hil
= calloc(1, sizeof(*hil
));
1280 hil
->tag
= strdup(new_email_addr
);
1281 handle_info_list_init(hil
);
1282 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1284 handle_info_list_append(hil
, hi
);
1285 hi
->email_addr
= hil
->tag
;
1289 static NICKSERV_FUNC(cmd_register
)
1292 struct handle_info
*hi
;
1293 const char *email_addr
, *password
;
1294 char syncpass
[MD5_CRYPT_LENGTH
];
1295 int no_auth
, weblink
;
1297 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1298 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1302 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1303 /* Require the first handle registered to belong to someone +o. */
1304 reply("NSMSG_REQUIRE_OPER");
1308 if (user
->handle_info
) {
1309 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1313 if (IsRegistering(user
)) {
1314 reply("NSMSG_ALREADY_REGISTERING");
1318 if (IsStamped(user
)) {
1319 /* Unauthenticated users might still have been stamped
1320 previously and could therefore have a hidden host;
1321 do not allow them to register a new account. */
1322 reply("NSMSG_STAMPED_REGISTER");
1326 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1328 if(nickserv_conf
.force_handles_lowercase
)
1329 irc_strtolower(argv
[1]);
1330 if (!is_valid_handle(argv
[1])) {
1331 reply("NSMSG_BAD_HANDLE", argv
[1]);
1336 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1337 struct handle_info_list
*hil
;
1340 /* Remember email address. */
1341 email_addr
= argv
[3];
1343 /* Check that the email address looks valid.. */
1344 if (!valid_email(email_addr
)) {
1345 reply("NSMSG_BAD_EMAIL_ADDR");
1349 /* .. and that we are allowed to send to it. */
1350 if ((str
= sendmail_prohibited_address(email_addr
))) {
1351 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1355 /* If we do email verify, make sure we don't spam the address. */
1356 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1358 for (nn
=0; nn
<hil
->used
; nn
++) {
1359 if (hil
->list
[nn
]->cookie
) {
1360 reply("NSMSG_EMAIL_UNACTIVATED");
1364 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1365 reply("NSMSG_EMAIL_OVERUSED");
1378 /* Webregister hack - send URL instead of IRC cookie
1381 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1385 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1387 /* Add any masks they should get. */
1388 if (nickserv_conf
.default_hostmask
) {
1389 string_list_append(hi
->masks
, strdup("*@*"));
1391 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1392 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1393 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1396 /* If they're the first to register, give them level 1000. */
1397 if (dict_size(nickserv_handle_dict
) == 1) {
1398 hi
->opserv_level
= 1000;
1399 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1402 /* Set their email address. */
1405 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1407 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email_addr
)) != LDAP_SUCCESS
) {
1408 /* Falied to update email in ldap, but still
1409 * updated it here.. what should we do? */
1410 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1412 nickserv_set_email_addr(hi
, email_addr
);
1416 nickserv_set_email_addr(hi
, email_addr
);
1419 nickserv_set_email_addr(hi
, email_addr
);
1423 /* If they need to do email verification, tell them. */
1425 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1427 /* Set registering flag.. */
1428 user
->modes
|= FLAGS_REGISTERING
;
1430 if (nickserv_conf
.sync_log
) {
1431 cryptpass(password
, syncpass
);
1433 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1434 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1437 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1440 /* this wont work if email is required .. */
1441 process_adduser_pending(user
);
1446 static NICKSERV_FUNC(cmd_oregister
)
1448 struct userNode
*settee
= NULL
;
1449 struct handle_info
*hi
;
1450 char* account
= NULL
;
1456 NICKSERV_MIN_PARMS(3);
1460 if(nickserv_conf
.force_handles_lowercase
)
1461 irc_strtolower(account
);
1462 if (nickserv_conf
.email_required
) {
1463 NICKSERV_MIN_PARMS(4);
1465 if (argc
>= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1466 if (strchr(argv
[4], '@') || argc
>= 6) /* If @, its mask not nick */
1476 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1477 if (strchr(argv
[3], '@') || argc
>= 5) /* If @, its mask not nick */
1486 /* If they passed a nick, look for that user.. */
1487 if (nick
&& !(settee
= GetUserH(nick
))) {
1488 reply("MSG_NICK_UNKNOWN", argv
[4]);
1491 /* If the setee is already authed, we cant add a 2nd account for them.. */
1492 if (settee
&& settee
->handle_info
) {
1493 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1496 /* If there is no default mask in the conf, and they didn't pass a mask,
1497 * but we did find a user by nick, generate the mask */
1499 if (nickserv_conf
.default_hostmask
)
1502 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1504 reply("NSMSG_REGISTER_BAD_NICKMASK");
1509 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1510 return 0; /* error reply handled by above */
1514 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1516 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email
)) != LDAP_SUCCESS
) {
1517 /* Falied to update email in ldap, but still
1518 * updated it here.. what should we do? */
1519 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1521 nickserv_set_email_addr(hi
, email
);
1525 nickserv_set_email_addr(hi
, email
);
1528 nickserv_set_email_addr(hi
, email
);
1532 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1533 string_list_append(hi
->masks
, mask_canonicalized
);
1536 if (nickserv_conf
.sync_log
)
1537 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1542 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1545 struct userNode
*target
;
1546 char *new_mask
= strdup(pretty_mask(mask
));
1547 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1548 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1549 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1554 string_list_append(hi
->ignores
, new_mask
);
1555 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1557 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1558 irc_silence(target
, new_mask
, 1);
1563 static NICKSERV_FUNC(cmd_addignore
)
1565 NICKSERV_MIN_PARMS(2);
1567 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1570 static NICKSERV_FUNC(cmd_oaddignore
)
1572 struct handle_info
*hi
;
1574 NICKSERV_MIN_PARMS(3);
1575 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1578 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1582 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1585 struct userNode
*target
;
1586 char *pmask
= strdup(pretty_mask(del_mask
));
1587 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1588 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1589 char *old_mask
= hi
->ignores
->list
[i
];
1590 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1591 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1592 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1593 irc_silence(target
, old_mask
, 0);
1600 reply("NSMSG_DELMASK_NOT_FOUND");
1604 static NICKSERV_FUNC(cmd_delignore
)
1606 NICKSERV_MIN_PARMS(2);
1607 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1610 static NICKSERV_FUNC(cmd_odelignore
)
1612 struct handle_info
*hi
;
1613 NICKSERV_MIN_PARMS(3);
1614 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1616 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1619 static NICKSERV_FUNC(cmd_handleinfo
)
1622 unsigned int i
, pos
=0, herelen
;
1623 struct userNode
*target
, *next_un
;
1624 struct handle_info
*hi
;
1625 const char *nsmsg_none
;
1628 if (!(hi
= user
->handle_info
)) {
1629 reply("NSMSG_MUST_AUTH");
1632 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1636 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1637 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1639 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1642 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1643 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1645 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1648 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1649 if (HANDLE_FLAGGED(hi
, FROZEN
))
1650 reply("NSMSG_HANDLEINFO_VACATION");
1652 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1653 struct do_not_register
*dnr
;
1654 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1655 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1656 if (!oper_outranks(cmd
, user
, hi
))
1658 } else if (hi
!= user
->handle_info
) {
1659 reply("NSMSG_HANDLEINFO_END");
1663 if (nickserv_conf
.email_enabled
)
1664 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1668 switch (hi
->cookie
->type
) {
1669 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1670 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1671 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1672 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1673 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1679 unsigned long flen
= 1;
1680 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1682 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1683 if (hi
->flags
& 1 << i
)
1684 flags
[flen
++] = handle_flags
[i
];
1686 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1688 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1691 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1692 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1693 || (hi
->opserv_level
> 0)) {
1694 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1697 if (IsHelping(user
) || IsOper(user
))
1702 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1703 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1708 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1710 if (hi
->last_quit_host
[0])
1711 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1713 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1715 if (nickserv_conf
.disable_nicks
) {
1716 /* nicks disabled; don't show anything about registered nicks */
1717 } else if (hi
->nicks
) {
1718 struct nick_info
*ni
, *next_ni
;
1719 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1720 herelen
= strlen(ni
->nick
);
1721 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1723 goto print_nicks_buff
;
1727 memcpy(buff
+pos
, ni
->nick
, herelen
);
1728 pos
+= herelen
; buff
[pos
++] = ' ';
1732 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1737 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1740 if (hi
->masks
->used
) {
1741 for (i
=0; i
< hi
->masks
->used
; i
++) {
1742 herelen
= strlen(hi
->masks
->list
[i
]);
1743 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1745 goto print_mask_buff
;
1747 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1748 pos
+= herelen
; buff
[pos
++] = ' ';
1749 if (i
+1 == hi
->masks
->used
) {
1752 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1757 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1760 if (hi
->ignores
->used
) {
1761 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1762 herelen
= strlen(hi
->ignores
->list
[i
]);
1763 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1765 goto print_ignore_buff
;
1767 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1768 pos
+= herelen
; buff
[pos
++] = ' ';
1769 if (i
+1 == hi
->ignores
->used
) {
1772 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1777 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1781 struct userData
*channel
, *next
;
1784 for (channel
= hi
->channels
; channel
; channel
= next
) {
1785 next
= channel
->u_next
;
1786 name
= channel
->channel
->channel
->name
;
1787 herelen
= strlen(name
);
1788 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1790 goto print_chans_buff
;
1792 if (IsUserSuspended(channel
))
1794 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1798 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1803 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1806 for (target
= hi
->users
; target
; target
= next_un
) {
1807 herelen
= strlen(target
->nick
);
1808 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1810 goto print_cnick_buff
;
1812 next_un
= target
->next_authed
;
1814 memcpy(buff
+pos
, target
->nick
, herelen
);
1815 pos
+= herelen
; buff
[pos
++] = ' ';
1819 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1824 reply("NSMSG_HANDLEINFO_END");
1828 static NICKSERV_FUNC(cmd_userinfo
)
1830 struct userNode
*target
;
1832 NICKSERV_MIN_PARMS(2);
1833 if (!(target
= GetUserH(argv
[1]))) {
1834 reply("MSG_NICK_UNKNOWN", argv
[1]);
1837 if (target
->handle_info
)
1838 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1840 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1844 static NICKSERV_FUNC(cmd_nickinfo
)
1846 struct nick_info
*ni
;
1848 NICKSERV_MIN_PARMS(2);
1849 if (!(ni
= get_nick_info(argv
[1]))) {
1850 reply("MSG_NICK_UNKNOWN", argv
[1]);
1853 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1857 static NICKSERV_FUNC(cmd_rename_handle
)
1859 struct handle_info
*hi
;
1860 struct userNode
*uNode
;
1864 NICKSERV_MIN_PARMS(3);
1865 if(nickserv_conf
.force_handles_lowercase
)
1866 irc_strtolower(argv
[2]);
1867 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
1869 if (!is_valid_handle(argv
[2])) {
1870 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1873 if (get_handle_info(argv
[2])) {
1874 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1877 if(strlen(argv
[2]) > 15)
1879 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1883 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1885 if( (rc
= ldap_rename_account(hi
->handle
, argv
[2])) != LDAP_SUCCESS
) {
1886 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1892 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1893 hi
->handle
= strdup(argv
[2]);
1894 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1895 for (nn
=0; nn
<rf_list_used
; nn
++)
1896 rf_list
[nn
](hi
, old_handle
);
1898 if (nickserv_conf
.sync_log
) {
1899 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1900 irc_rename(uNode
, hi
->handle
);
1902 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1905 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1906 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1907 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1913 static failpw_func_t
*failpw_func_list
;
1914 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1917 reg_failpw_func(failpw_func_t func
)
1919 if (failpw_func_used
== failpw_func_size
) {
1920 if (failpw_func_size
) {
1921 failpw_func_size
<<= 1;
1922 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1924 failpw_func_size
= 8;
1925 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1928 failpw_func_list
[failpw_func_used
++] = func
;
1932 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1934 * called by nefariouses enhanced AC login-on-connect code
1937 struct handle_info
*loc_auth(char *handle
, char *password
)
1939 int pw_arg
, used
, maxlogins
;
1942 struct handle_info
*hi
;
1943 struct userNode
*other
;
1945 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
) {
1962 if (!checkpass(password
, hi
->passwd
)) {
1967 if( (!hi
) && nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
1968 /* user not found, but authed to ldap successfully..
1969 * create the account.
1974 /* Add a *@* mask */
1975 if(nickserv_conf
.default_hostmask
)
1978 return NULL
; /* They dont have a *@* mask so they can't loc */
1980 if(!(hi
= nickserv_register(NULL
, NULL
, handle
, password
, 0))) {
1981 return 0; /* couldn't add the user for some reason */
1984 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
1986 if(nickserv_conf
.email_required
) {
1991 nickserv_set_email_addr(hi
, email
);
1995 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1996 string_list_append(hi
->masks
, mask_canonicalized
);
1998 if(nickserv_conf
.sync_log
)
1999 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, "@", handle
);
2003 /* Still no account, so just fail out */
2008 /* We don't know the users hostname, or anything because they
2009 * havn't registered yet. So we can only allow LOC if your
2010 * account has *@* as a hostmask.
2012 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2014 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
2023 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2027 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2028 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2029 if (++used
>= maxlogins
) {
2033 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2037 static NICKSERV_FUNC(cmd_auth
)
2039 int pw_arg
, used
, maxlogins
;
2040 struct handle_info
*hi
;
2042 struct userNode
*other
;
2044 int ldap_result
= LDAP_OTHER
;
2048 if (user
->handle_info
) {
2049 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2052 if (IsStamped(user
)) {
2053 /* Unauthenticated users might still have been stamped
2054 previously and could therefore have a hidden host;
2055 do not allow them to authenticate. */
2056 reply("NSMSG_STAMPED_AUTH");
2061 if(strchr(argv
[1], '<') || strchr(argv
[1], '>')) {
2062 reply("NSMSG_NO_ANGLEBRACKETS");
2065 if (!is_valid_handle(argv
[1])) {
2066 reply("NSMSG_BAD_HANDLE", argv
[1]);
2070 if(nickserv_conf
.ldap_enable
) {
2071 ldap_result
= ldap_check_auth(argv
[1], argv
[2]);
2072 /* Get the users email address and update it */
2073 if(ldap_result
== LDAP_SUCCESS
) {
2075 if((rc
= ldap_get_user_info(argv
[1], &email
) != LDAP_SUCCESS
))
2077 if(nickserv_conf
.email_required
) {
2078 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc
));
2083 else if(ldap_result
!= LDAP_INVALID_CREDENTIALS
) {
2084 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2090 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
2092 } else if (argc
== 2) {
2093 if (nickserv_conf
.disable_nicks
) {
2094 if (!(hi
= get_handle_info(user
->nick
))) {
2095 reply("NSMSG_HANDLE_NOT_FOUND");
2099 /* try to look up their handle from their nick */
2100 /* TODO: handle ldap auth on nickserv style networks, too */
2101 struct nick_info
*ni
;
2102 ni
= get_nick_info(user
->nick
);
2104 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
2111 reply("MSG_MISSING_PARAMS", argv
[0]);
2112 svccmd_send_help_brief(user
, nickserv
, cmd
);
2117 if(nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2118 /* user not found, but authed to ldap successfully..
2119 * create the account.
2122 if(!(hi
= nickserv_register(user
, NULL
, argv
[1], argv
[2], 0))) {
2123 reply("NSMSG_UNABLE_TO_ADD");
2124 return 0; /* couldn't add the user for some reason */
2126 /* Add a *@* mask */
2127 if(nickserv_conf
.default_hostmask
)
2130 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2133 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2134 string_list_append(hi
->masks
, mask_canonicalized
);
2137 nickserv_set_email_addr(hi
, email
);
2140 if(nickserv_conf
.sync_log
)
2141 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
);
2145 reply("NSMSG_HANDLE_NOT_FOUND");
2151 /* Responses from here on look up the language used by the handle they asked about. */
2152 passwd
= argv
[pw_arg
];
2153 if (!valid_user_for(user
, hi
)) {
2154 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
2155 send_message_type(4, user
, cmd
->parent
->bot
,
2156 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
2159 send_message_type(4, user
, cmd
->parent
->bot
,
2160 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
2162 argv
[pw_arg
] = "BADMASK";
2166 if( ( nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_INVALID_CREDENTIALS
) ||
2167 ( !nickserv_conf
.ldap_enable
&& !checkpass(passwd
, hi
->passwd
) ) ) {
2169 if (!checkpass(passwd
, hi
->passwd
)) {
2172 send_message_type(4, user
, cmd
->parent
->bot
,
2173 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
2174 argv
[pw_arg
] = "BADPASS";
2175 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
2176 if (nickserv_conf
.autogag_enabled
) {
2177 if (!user
->auth_policer
.params
) {
2178 user
->auth_policer
.last_req
= now
;
2179 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
2181 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
2183 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
2184 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
2185 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2187 argv
[pw_arg
] = "GAGGED";
2192 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2193 send_message_type(4, user
, cmd
->parent
->bot
,
2194 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2195 argv
[pw_arg
] = "SUSPENDED";
2198 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2199 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2200 if (++used
>= maxlogins
) {
2201 send_message_type(4, user
, cmd
->parent
->bot
,
2202 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2204 argv
[pw_arg
] = "MAXLOGINS";
2209 set_user_handle_info(user
, hi
, 1);
2210 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2211 reply("NSMSG_PLEASE_SET_EMAIL");
2212 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2213 reply("NSMSG_WEAK_PASSWORD");
2214 if (hi
->passwd
[0] != '$')
2215 cryptpass(passwd
, hi
->passwd
);
2217 /* If a channel was waiting for this user to auth,
2218 * finish adding them */
2219 process_adduser_pending(user
);
2221 reply("NSMSG_AUTH_SUCCESS");
2224 /* Set +x if autohide is on */
2225 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2226 irc_umode(user
, "+x");
2228 if(!IsOper(user
)) /* If they arnt already opered.. */
2230 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2231 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2233 irc_umode(user
,nickserv_conf
.auto_admin
);
2234 reply("NSMSG_AUTO_OPER_ADMIN");
2236 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2238 irc_umode(user
,nickserv_conf
.auto_oper
);
2239 reply("NSMSG_AUTO_OPER");
2243 /* Wipe out the pass for the logs */
2244 argv
[pw_arg
] = "****";
2248 static allowauth_func_t
*allowauth_func_list
;
2249 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2252 reg_allowauth_func(allowauth_func_t func
)
2254 if (allowauth_func_used
== allowauth_func_size
) {
2255 if (allowauth_func_size
) {
2256 allowauth_func_size
<<= 1;
2257 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2259 allowauth_func_size
= 8;
2260 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2263 allowauth_func_list
[allowauth_func_used
++] = func
;
2266 static NICKSERV_FUNC(cmd_allowauth
)
2268 struct userNode
*target
;
2269 struct handle_info
*hi
;
2272 NICKSERV_MIN_PARMS(2);
2273 if (!(target
= GetUserH(argv
[1]))) {
2274 reply("MSG_NICK_UNKNOWN", argv
[1]);
2277 if (target
->handle_info
) {
2278 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2281 if (IsStamped(target
)) {
2282 /* Unauthenticated users might still have been stamped
2283 previously and could therefore have a hidden host;
2284 do not allow them to authenticate to an account. */
2285 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2290 else if (!(hi
= get_handle_info(argv
[2]))) {
2291 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2295 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2296 reply("MSG_USER_OUTRANKED", hi
->handle
);
2299 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2300 || (hi
->opserv_level
> 0))
2301 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2302 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2305 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2306 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2307 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2308 if (nickserv_conf
.email_enabled
)
2309 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2311 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2312 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2314 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2316 for (n
=0; n
<allowauth_func_used
; n
++)
2317 allowauth_func_list
[n
](user
, target
, hi
);
2321 static NICKSERV_FUNC(cmd_authcookie
)
2323 struct handle_info
*hi
;
2325 NICKSERV_MIN_PARMS(2);
2326 if (user
->handle_info
) {
2327 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2330 if (IsStamped(user
)) {
2331 /* Unauthenticated users might still have been stamped
2332 previously and could therefore have a hidden host;
2333 do not allow them to authenticate to an account. */
2334 reply("NSMSG_STAMPED_AUTHCOOKIE");
2337 if (!(hi
= get_handle_info(argv
[1]))) {
2338 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2341 if (!hi
->email_addr
) {
2342 reply("MSG_SET_EMAIL_ADDR");
2345 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2349 static NICKSERV_FUNC(cmd_delcookie
)
2351 struct handle_info
*hi
;
2353 hi
= user
->handle_info
;
2355 reply("NSMSG_NO_COOKIE");
2358 switch (hi
->cookie
->type
) {
2361 reply("NSMSG_MUST_TIME_OUT");
2364 nickserv_eat_cookie(hi
->cookie
);
2365 reply("NSMSG_ATE_COOKIE");
2371 static NICKSERV_FUNC(cmd_odelcookie
)
2373 struct handle_info
*hi
;
2375 NICKSERV_MIN_PARMS(2);
2377 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2381 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2385 switch (hi
->cookie
->type
) {
2387 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2388 if (nickserv_conf
.sync_log
)
2389 SyncLog("ACCOUNTACC %s", hi
->handle
);
2391 case PASSWORD_CHANGE
:
2392 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2393 if (nickserv_conf
.sync_log
)
2394 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2397 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2398 if (nickserv_conf
.sync_log
)
2399 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2402 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2404 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2405 /* Falied to update email in ldap, but still
2406 * updated it here.. what should we do? */
2407 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2409 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2413 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2416 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2418 if (nickserv_conf
.sync_log
)
2419 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2422 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2423 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2427 nickserv_eat_cookie(hi
->cookie
);
2428 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2433 static NICKSERV_FUNC(cmd_resetpass
)
2435 struct handle_info
*hi
;
2436 char crypted
[MD5_CRYPT_LENGTH
];
2439 NICKSERV_MIN_PARMS(3);
2440 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2444 if (user
->handle_info
) {
2445 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2448 if (IsStamped(user
)) {
2449 /* Unauthenticated users might still have been stamped
2450 previously and could therefore have a hidden host;
2451 do not allow them to activate an account. */
2452 reply("NSMSG_STAMPED_RESETPASS");
2455 if (!(hi
= get_handle_info(argv
[1]))) {
2456 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2459 if (!hi
->email_addr
) {
2460 reply("MSG_SET_EMAIL_ADDR");
2463 cryptpass(argv
[2], crypted
);
2465 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2469 static NICKSERV_FUNC(cmd_cookie
)
2471 struct handle_info
*hi
;
2474 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2477 NICKSERV_MIN_PARMS(3);
2478 if (!(hi
= get_handle_info(argv
[1]))) {
2479 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2485 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2486 reply("NSMSG_HANDLE_SUSPENDED");
2491 reply("NSMSG_NO_COOKIE");
2495 /* Check validity of operation before comparing cookie to
2496 * prohibit guessing by authed users. */
2497 if (user
->handle_info
2498 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2499 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2500 reply("NSMSG_CANNOT_COOKIE");
2504 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2505 reply("NSMSG_BAD_COOKIE");
2509 switch (hi
->cookie
->type
) {
2512 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2514 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2515 /* Falied to update email in ldap, but still
2516 * updated it here.. what should we do? */
2517 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2522 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2523 set_user_handle_info(user
, hi
, 1);
2524 reply("NSMSG_HANDLE_ACTIVATED");
2525 if (nickserv_conf
.sync_log
)
2526 SyncLog("ACCOUNTACC %s", hi
->handle
);
2528 case PASSWORD_CHANGE
:
2530 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2532 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2533 /* Falied to update email in ldap, but still
2534 * updated it here.. what should we do? */
2535 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2540 set_user_handle_info(user
, hi
, 1);
2541 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2542 reply("NSMSG_PASSWORD_CHANGED");
2543 if (nickserv_conf
.sync_log
)
2544 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2548 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2550 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2551 /* Falied to update email in ldap, but still
2552 * updated it here.. what should we do? */
2553 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2558 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2560 * This should only happen if an OREGISTER was sent. Require
2561 * email must be enabled! - SiRVulcaN
2563 if (nickserv_conf
.sync_log
)
2564 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2567 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2568 reply("NSMSG_EMAIL_CHANGED");
2569 if (nickserv_conf
.sync_log
)
2570 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2573 set_user_handle_info(user
, hi
, 1);
2574 reply("NSMSG_AUTH_SUCCESS");
2577 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2578 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2582 nickserv_eat_cookie(hi
->cookie
);
2584 process_adduser_pending(user
);
2589 static NICKSERV_FUNC(cmd_oregnick
) {
2591 struct handle_info
*target
;
2592 struct nick_info
*ni
;
2594 NICKSERV_MIN_PARMS(3);
2595 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2598 if (!is_registerable_nick(nick
)) {
2599 reply("NSMSG_BAD_NICK", nick
);
2602 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2604 reply("NSMSG_NICK_EXISTS", nick
);
2607 register_nick(nick
, target
);
2608 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2612 static NICKSERV_FUNC(cmd_regnick
) {
2614 struct nick_info
*ni
;
2616 if (!is_registerable_nick(user
->nick
)) {
2617 reply("NSMSG_BAD_NICK", user
->nick
);
2620 /* count their nicks, see if it's too many */
2621 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2622 if (n
>= nickserv_conf
.nicks_per_handle
) {
2623 reply("NSMSG_TOO_MANY_NICKS");
2626 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2628 reply("NSMSG_NICK_EXISTS", user
->nick
);
2631 register_nick(user
->nick
, user
->handle_info
);
2632 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2636 static NICKSERV_FUNC(cmd_pass
)
2638 struct handle_info
*hi
;
2639 char *old_pass
, *new_pass
;
2640 char crypted
[MD5_CRYPT_LENGTH
+1];
2645 NICKSERV_MIN_PARMS(3);
2646 hi
= user
->handle_info
;
2650 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2653 if(nickserv_conf
.ldap_enable
) {
2654 ldap_result
= ldap_check_auth(hi
->handle
, old_pass
);
2655 if(ldap_result
!= LDAP_SUCCESS
) {
2656 if(ldap_result
== LDAP_INVALID_CREDENTIALS
)
2657 reply("NSMSG_PASSWORD_INVALID");
2659 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2664 if (!checkpass(old_pass
, hi
->passwd
)) {
2665 argv
[1] = "BADPASS";
2666 reply("NSMSG_PASSWORD_INVALID");
2669 cryptpass(new_pass
, crypted
);
2671 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2673 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
2674 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2679 //cryptpass(new_pass, hi->passwd);
2680 strcpy(hi
->passwd
, crypted
);
2681 if (nickserv_conf
.sync_log
)
2682 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2684 reply("NSMSG_PASS_SUCCESS");
2689 nickserv_addmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2692 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2693 for (i
=0; i
<hi
->masks
->used
; i
++) {
2694 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2695 reply("NSMSG_ADDMASK_ALREADY", new_mask
);
2700 string_list_append(hi
->masks
, new_mask
);
2701 reply("NSMSG_ADDMASK_SUCCESS", new_mask
);
2705 static NICKSERV_FUNC(cmd_addmask
)
2708 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2709 int res
= nickserv_addmask(cmd
, user
, user
->handle_info
, mask
);
2713 if (!is_gline(argv
[1])) {
2714 reply("NSMSG_MASK_INVALID", argv
[1]);
2717 return nickserv_addmask(cmd
, user
, user
->handle_info
, argv
[1]);
2721 static NICKSERV_FUNC(cmd_oaddmask
)
2723 struct handle_info
*hi
;
2725 NICKSERV_MIN_PARMS(3);
2726 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2728 return nickserv_addmask(cmd
, user
, hi
, argv
[2]);
2732 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2735 for (i
=0; i
<hi
->masks
->used
; i
++) {
2736 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2737 char *old_mask
= hi
->masks
->list
[i
];
2738 if (hi
->masks
->used
== 1) {
2739 reply("NSMSG_DELMASK_NOTLAST");
2742 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2743 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2748 reply("NSMSG_DELMASK_NOT_FOUND");
2752 static NICKSERV_FUNC(cmd_delmask
)
2754 NICKSERV_MIN_PARMS(2);
2755 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1]);
2758 static NICKSERV_FUNC(cmd_odelmask
)
2760 struct handle_info
*hi
;
2761 NICKSERV_MIN_PARMS(3);
2762 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2764 return nickserv_delmask(cmd
, user
, hi
, argv
[2]);
2768 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2769 unsigned int nn
, add
= 1, pos
;
2770 unsigned long added
, removed
, flag
;
2772 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2774 case '+': add
= 1; break;
2775 case '-': add
= 0; break;
2777 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2778 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2781 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2782 /* cheesy avoidance of looking up the flag name.. */
2783 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2786 flag
= 1 << (pos
- 1);
2788 added
|= flag
, removed
&= ~flag
;
2790 removed
|= flag
, added
&= ~flag
;
2795 *premoved
= removed
;
2800 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2802 unsigned long before
, after
, added
, removed
;
2803 struct userNode
*uNode
;
2805 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2806 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2808 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2809 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2811 /* Strip helping flag if they're only a support helper and not
2812 * currently in #support. */
2813 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2814 struct channelList
*schannels
;
2816 schannels
= chanserv_support_channels();
2817 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2818 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2819 if (GetUserMode(schannels
->list
[ii
], uNode
))
2821 if (ii
< schannels
->used
)
2825 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2828 if (after
&& !before
) {
2829 /* Add user to current helper list. */
2830 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2831 userList_append(&curr_helpers
, uNode
);
2832 } else if (!after
&& before
) {
2833 /* Remove user from current helper list. */
2834 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2835 userList_remove(&curr_helpers
, uNode
);
2842 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2846 char *set_display
[] = {
2847 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2848 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2849 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2852 reply("NSMSG_SETTING_LIST");
2853 reply("NSMSG_SETTING_LIST_HEADER");
2855 /* Do this so options are presented in a consistent order. */
2856 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2857 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2858 opt(cmd
, user
, hi
, override
, 0, NULL
);
2859 reply("NSMSG_SETTING_LIST_END");
2862 static NICKSERV_FUNC(cmd_set
)
2864 struct handle_info
*hi
;
2867 hi
= user
->handle_info
;
2869 set_list(cmd
, user
, hi
, 0);
2872 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2873 reply("NSMSG_INVALID_OPTION", argv
[1]);
2876 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2879 static NICKSERV_FUNC(cmd_oset
)
2881 struct handle_info
*hi
;
2884 NICKSERV_MIN_PARMS(2);
2886 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
2890 set_list(cmd
, user
, hi
, 0);
2894 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2895 reply("NSMSG_INVALID_OPTION", argv
[2]);
2899 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
2902 static OPTION_FUNC(opt_info
)
2906 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2908 hi
->infoline
= NULL
;
2910 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2914 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2915 reply("NSMSG_SET_INFO", info
);
2919 static OPTION_FUNC(opt_width
)
2922 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2924 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2925 hi
->screen_width
= MIN_LINE_SIZE
;
2926 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2927 hi
->screen_width
= MAX_LINE_SIZE
;
2929 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
2933 static OPTION_FUNC(opt_tablewidth
)
2936 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2938 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2939 hi
->table_width
= MIN_LINE_SIZE
;
2940 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2941 hi
->table_width
= MAX_LINE_SIZE
;
2943 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2947 static OPTION_FUNC(opt_color
)
2950 if (enabled_string(argv
[1]))
2951 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2952 else if (disabled_string(argv
[1]))
2953 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2955 reply("MSG_INVALID_BINARY", argv
[1]);
2960 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2964 static OPTION_FUNC(opt_privmsg
)
2967 if (enabled_string(argv
[1]))
2968 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2969 else if (disabled_string(argv
[1]))
2970 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2972 reply("MSG_INVALID_BINARY", argv
[1]);
2977 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2981 static OPTION_FUNC(opt_autohide
)
2984 if (enabled_string(argv
[1]))
2985 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2986 else if (disabled_string(argv
[1]))
2987 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2989 reply("MSG_INVALID_BINARY", argv
[1]);
2994 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2998 static OPTION_FUNC(opt_style
)
3003 if (!irccasecmp(argv
[1], "Clean"))
3004 hi
->userlist_style
= HI_STYLE_CLEAN
;
3005 else if (!irccasecmp(argv
[1], "Advanced"))
3006 hi
->userlist_style
= HI_STYLE_ADVANCED
;
3007 else if (!irccasecmp(argv
[1], "Classic"))
3008 hi
->userlist_style
= HI_STYLE_CLASSIC
;
3009 else /* Default to normal */
3010 hi
->userlist_style
= HI_STYLE_NORMAL
;
3011 } /* TODO: give error if unknow style is chosen */
3013 switch (hi
->userlist_style
) {
3014 case HI_STYLE_ADVANCED
:
3017 case HI_STYLE_CLASSIC
:
3020 case HI_STYLE_CLEAN
:
3023 case HI_STYLE_NORMAL
:
3028 reply("NSMSG_SET_STYLE", style
);
3032 static OPTION_FUNC(opt_announcements
)
3037 if (enabled_string(argv
[1]))
3038 hi
->announcements
= 'y';
3039 else if (disabled_string(argv
[1]))
3040 hi
->announcements
= 'n';
3041 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
3042 hi
->announcements
= '?';
3044 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
3049 switch (hi
->announcements
) {
3050 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
3051 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
3052 case '?': choice
= "default"; break;
3053 default: choice
= "unknown"; break;
3055 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
3059 static OPTION_FUNC(opt_password
)
3061 char crypted
[MD5_CRYPT_LENGTH
+1];
3066 reply("NSMSG_USE_CMD_PASS");
3070 cryptpass(argv
[1], crypted
);
3072 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3074 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
3075 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3080 strcpy(hi
->passwd
, crypted
);
3081 if (nickserv_conf
.sync_log
)
3082 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
3084 reply("NSMSG_SET_PASSWORD", "***");
3088 static OPTION_FUNC(opt_flags
)
3091 unsigned int ii
, flen
;
3094 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3099 nickserv_apply_flags(user
, hi
, argv
[1]);
3101 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
3102 if (hi
->flags
& (1 << ii
))
3103 flags
[flen
++] = handle_flags
[ii
];
3106 reply("NSMSG_SET_FLAGS", flags
);
3108 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
3112 static OPTION_FUNC(opt_email
)
3116 if (!valid_email(argv
[1])) {
3117 reply("NSMSG_BAD_EMAIL_ADDR");
3120 if ((str
= sendmail_prohibited_address(argv
[1]))) {
3121 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
3124 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
3125 reply("NSMSG_EMAIL_SAME");
3127 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
3130 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3132 if((rc
= ldap_do_modify(hi
->handle
, NULL
, argv
[1])) != LDAP_SUCCESS
) {
3133 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3138 nickserv_set_email_addr(hi
, argv
[1]);
3140 nickserv_eat_cookie(hi
->cookie
);
3141 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3144 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3148 static OPTION_FUNC(opt_maxlogins
)
3150 unsigned char maxlogins
;
3152 maxlogins
= strtoul(argv
[1], NULL
, 0);
3153 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
3154 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
3157 hi
->maxlogins
= maxlogins
;
3159 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
3160 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
3164 static OPTION_FUNC(opt_advanced
)
3167 if (enabled_string(argv
[1]))
3168 HANDLE_SET_FLAG(hi
, ADVANCED
);
3169 else if (disabled_string(argv
[1]))
3170 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
3172 reply("MSG_INVALID_BINARY", argv
[1]);
3177 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
3181 static OPTION_FUNC(opt_language
)
3183 struct language
*lang
;
3185 lang
= language_find(argv
[1]);
3186 if (irccasecmp(lang
->name
, argv
[1]))
3187 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
3188 hi
->language
= lang
;
3190 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
3194 /* Called from opserv from cmd_access */
3196 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
3197 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
3199 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
3200 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
3201 && (user
->handle_info
->opserv_level
< 1000))) {
3202 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
3205 if ((user
->handle_info
->opserv_level
< new_level
)
3206 || ((user
->handle_info
->opserv_level
== new_level
)
3207 && (user
->handle_info
->opserv_level
< 1000))) {
3208 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
3211 if (user
->handle_info
== target
) {
3212 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
3216 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_oper_group_dn
&& nickserv_conf
.ldap_admin_dn
) {
3219 rc
= ldap_add2group(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3221 rc
= ldap_delfromgroup(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3222 if(rc
!= LDAP_SUCCESS
&& rc
!= LDAP_TYPE_OR_VALUE_EXISTS
&& rc
!= LDAP_NO_SUCH_ATTRIBUTE
) {
3223 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3228 if (target
->opserv_level
== new_level
)
3230 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
3231 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
3232 target
->opserv_level
= new_level
;
3236 static OPTION_FUNC(opt_level
)
3241 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3245 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
3246 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
3250 static OPTION_FUNC(opt_epithet
)
3252 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
3254 struct userNode
*target
, *next_un
;
3257 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3261 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
3265 if ((epithet
[0] == '*') && !epithet
[1])
3268 hi
->epithet
= strdup(epithet
);
3270 for (target
= hi
->users
; target
; target
= next_un
) {
3271 irc_swhois(nickserv
, target
, hi
->epithet
);
3273 next_un
= target
->next_authed
;
3278 reply("NSMSG_SET_EPITHET", hi
->epithet
);
3280 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
3284 static OPTION_FUNC(opt_title
)
3290 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
3292 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3297 if(!strcmp(title
, "*")) {
3299 hi
->fakehost
= NULL
;
3302 if (strchr(title
, '.')) {
3303 reply("NSMSG_TITLE_INVALID");
3306 /* Alphanumeric titles only. */
3307 for(sptr
= title
; *sptr
; sptr
++) {
3308 if(!isalnum(*sptr
) && *sptr
!= '-') {
3309 reply("NSMSG_TITLE_INVALID");
3313 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
3314 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3315 reply("NSMSG_TITLE_TRUNCATED");
3319 hi
->fakehost
= malloc(strlen(title
)+2);
3320 hi
->fakehost
[0] = '.';
3321 strcpy(hi
->fakehost
+1, title
);
3324 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3325 title
= hi
->fakehost
+ 1;
3327 /* If theres no title set then the default title will therefore
3328 be the first part of hidden_host in x3.conf, so for
3329 consistency with opt_fakehost we will print this here.
3330 This isnt actually used in P10, its just handled to keep from crashing... */
3331 char *hs
, *hidden_suffix
, *rest
;
3333 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3334 hidden_suffix
= strdup(hs
);
3336 /* Yes we do this twice */
3337 if((rest
= strchr(hidden_suffix
, '.')))
3340 title
= hidden_suffix
;
3344 /* A lame default if someone configured hidden_host to something lame */
3345 title
= strdup("users");
3346 free(hidden_suffix
);
3352 none
= user_find_message(user
, "MSG_NONE");
3353 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3358 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3362 // check for a dot in the vhost
3363 if(strchr(vhost
, '.') == NULL
) {
3364 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3368 // check for a @ in the vhost
3369 if(strchr(vhost
, '@') != NULL
) {
3370 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3374 // check for denied words, inspired by monk at paki.sex
3375 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3376 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3377 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3382 // check for ircu's HOSTLEN length.
3383 if(strlen(vhost
) >= HOSTLEN
) {
3384 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3388 /* This can be handled by the regex now if desired.
3389 if (vhost[strspn(vhost, "0123456789.")]) {
3390 hostname = vhost + strlen(vhost);
3391 for (depth = 1; depth && (hostname > vhost); depth--) {
3393 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3396 if (*hostname == '.') hostname++; * advance past last dot we saw *
3397 if(strlen(hostname) > 4) {
3398 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3403 /* test either regex or as valid handle */
3404 if (nickserv_conf
.valid_fakehost_regex_set
) {
3405 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3408 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3409 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3411 if(err
== REG_NOMATCH
) {
3412 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3421 static OPTION_FUNC(opt_fakehost
)
3425 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3427 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3432 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3433 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3436 if (!strcmp(fake
, "*")) {
3439 hi
->fakehost
= NULL
;
3442 else if (!check_vhost(argv
[1], user
, cmd
)) {
3443 /* check_vhost takes care of error reply */
3449 hi
->fakehost
= strdup(fake
);
3452 fake
= hi
->fakehost
;
3454 fake
= generate_fakehost(hi
);
3456 /* Tell them we set the host */
3458 fake
= user_find_message(user
, "MSG_NONE");
3459 reply("NSMSG_SET_FAKEHOST", fake
);
3463 static OPTION_FUNC(opt_note
)
3466 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3471 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3476 if ((text
[0] == '*') && !text
[1])
3479 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3484 reply("NSMSG_SET_NOTE", hi
->note
? hi
->note
->note
: user_find_message(user
, "MSG_NONE"));
3488 static NICKSERV_FUNC(cmd_reclaim
)
3490 struct handle_info
*hi
;
3491 struct nick_info
*ni
;
3492 struct userNode
*victim
;
3494 NICKSERV_MIN_PARMS(2);
3495 hi
= user
->handle_info
;
3496 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3498 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3501 if (ni
->owner
!= user
->handle_info
) {
3502 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3505 victim
= GetUserH(ni
->nick
);
3507 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3510 if (victim
== user
) {
3511 reply("NSMSG_NICK_USER_YOU");
3514 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3515 switch (nickserv_conf
.reclaim_action
) {
3516 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3517 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3518 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3519 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3524 static NICKSERV_FUNC(cmd_unregnick
)
3527 struct handle_info
*hi
;
3528 struct nick_info
*ni
;
3530 hi
= user
->handle_info
;
3531 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3532 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3534 reply("NSMSG_UNKNOWN_NICK", nick
);
3537 if (hi
!= ni
->owner
) {
3538 reply("NSMSG_NOT_YOUR_NICK", nick
);
3541 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3546 static NICKSERV_FUNC(cmd_ounregnick
)
3548 struct nick_info
*ni
;
3550 NICKSERV_MIN_PARMS(2);
3551 if (!(ni
= get_nick_info(argv
[1]))) {
3552 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3555 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3556 reply("MSG_USER_OUTRANKED", ni
->nick
);
3559 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3564 static NICKSERV_FUNC(cmd_unregister
)
3566 struct handle_info
*hi
;
3569 NICKSERV_MIN_PARMS(2);
3570 hi
= user
->handle_info
;
3573 if (checkpass(passwd
, hi
->passwd
)) {
3574 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3579 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3580 reply("NSMSG_PASSWORD_INVALID");
3585 static NICKSERV_FUNC(cmd_ounregister
)
3587 struct handle_info
*hi
;
3589 NICKSERV_MIN_PARMS(2);
3590 if (!(hi
= get_victim_oper(cmd
, user
, argv
[1])))
3592 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3598 static NICKSERV_FUNC(cmd_status
)
3600 if (nickserv_conf
.disable_nicks
) {
3601 reply("NSMSG_GLOBAL_STATS_NONICK",
3602 dict_size(nickserv_handle_dict
));
3604 if (user
->handle_info
) {
3606 struct nick_info
*ni
;
3607 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3608 reply("NSMSG_HANDLE_STATS", cnt
);
3610 reply("NSMSG_HANDLE_NONE");
3612 reply("NSMSG_GLOBAL_STATS",
3613 dict_size(nickserv_handle_dict
),
3614 dict_size(nickserv_nick_dict
));
3619 static NICKSERV_FUNC(cmd_ghost
)
3621 struct userNode
*target
;
3622 char reason
[MAXLEN
];
3624 NICKSERV_MIN_PARMS(2);
3625 if (!(target
= GetUserH(argv
[1]))) {
3626 reply("MSG_NICK_UNKNOWN", argv
[1]);
3629 if (target
== user
) {
3630 reply("NSMSG_CANNOT_GHOST_SELF");
3633 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3634 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3637 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3638 DelUser(target
, nickserv
, 1, reason
);
3639 reply("NSMSG_GHOST_KILLED", argv
[1]);
3643 static NICKSERV_FUNC(cmd_vacation
)
3645 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3646 reply("NSMSG_ON_VACATION");
3651 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3653 struct handle_info
*hi
;
3656 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3658 saxdb_start_record(ctx
, iter_key(it
), 0);
3659 if (hi
->announcements
!= '?') {
3660 flags
[0] = hi
->announcements
;
3662 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3665 struct handle_cookie
*cookie
= hi
->cookie
;
3668 switch (cookie
->type
) {
3669 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3670 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3671 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3672 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3673 default: type
= NULL
; break;
3676 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3677 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3678 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3680 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3681 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3682 saxdb_end_record(ctx
);
3686 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3688 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3690 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3691 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3692 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3693 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3694 saxdb_end_record(ctx
);
3698 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3702 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3703 if (hi
->flags
& (1 << ii
))
3704 flags
[flen
++] = handle_flags
[ii
];
3706 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3709 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3710 if (hi
->last_quit_host
[0])
3711 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3712 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3713 if (hi
->masks
->used
)
3714 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3715 if (hi
->ignores
->used
)
3716 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3718 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3720 struct string_list
*slist
;
3721 struct nick_info
*ni
;
3723 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3724 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3725 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3729 if (hi
->opserv_level
)
3730 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3731 if (hi
->language
!= lang_C
)
3732 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3733 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3734 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3735 if (hi
->screen_width
)
3736 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3737 if (hi
->table_width
)
3738 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3739 flags
[0] = hi
->userlist_style
;
3741 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3742 saxdb_end_record(ctx
);
3748 static handle_merge_func_t
*handle_merge_func_list
;
3749 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3752 reg_handle_merge_func(handle_merge_func_t func
)
3754 if (handle_merge_func_used
== handle_merge_func_size
) {
3755 if (handle_merge_func_size
) {
3756 handle_merge_func_size
<<= 1;
3757 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3759 handle_merge_func_size
= 8;
3760 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3763 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3766 static NICKSERV_FUNC(cmd_merge
)
3768 struct handle_info
*hi_from
, *hi_to
;
3769 struct userNode
*last_user
;
3770 struct userData
*cList
, *cListNext
;
3771 unsigned int ii
, jj
, n
;
3773 NICKSERV_MIN_PARMS(3);
3775 if (!(hi_from
= get_victim_oper(cmd
, user
, argv
[1])))
3777 if (!(hi_to
= get_victim_oper(cmd
, user
, argv
[2])))
3779 if (hi_to
== hi_from
) {
3780 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3784 for (n
=0; n
<handle_merge_func_used
; n
++)
3785 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3787 /* Append "from" handle's nicks to "to" handle's nick list. */
3789 struct nick_info
*last_ni
;
3790 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3791 last_ni
->next
= hi_from
->nicks
;
3793 while (hi_from
->nicks
) {
3794 hi_from
->nicks
->owner
= hi_to
;
3795 hi_from
->nicks
= hi_from
->nicks
->next
;
3798 /* Merge the hostmasks. */
3799 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3800 char *mask
= hi_from
->masks
->list
[ii
];
3801 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3802 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3804 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3805 string_list_append(hi_to
->masks
, strdup(mask
));
3808 /* Merge the ignores. */
3809 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3810 char *ignore
= hi_from
->ignores
->list
[ii
];
3811 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3812 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3814 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3815 string_list_append(hi_to
->ignores
, strdup(ignore
));
3818 /* Merge the lists of authed users. */
3820 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3821 last_user
->next_authed
= hi_from
->users
;
3823 hi_to
->users
= hi_from
->users
;
3825 /* Repoint the old "from" handle's users. */
3826 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3827 last_user
->handle_info
= hi_to
;
3829 hi_from
->users
= NULL
;
3831 /* Merge channel userlists. */
3832 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3833 struct userData
*cList2
;
3834 cListNext
= cList
->u_next
;
3835 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3836 if (cList
->channel
== cList2
->channel
)
3838 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3839 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
);
3840 /* keep cList2 in hi_to; remove cList from hi_from */
3841 del_channel_user(cList
, 1);
3844 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
);
3845 /* remove the lower-ranking cList2 from hi_to */
3846 del_channel_user(cList2
, 1);
3848 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3850 /* cList needs to be moved from hi_from to hi_to */
3851 cList
->handle
= hi_to
;
3852 /* Remove from linked list for hi_from */
3853 assert(!cList
->u_prev
);
3854 hi_from
->channels
= cList
->u_next
;
3856 cList
->u_next
->u_prev
= cList
->u_prev
;
3857 /* Add to linked list for hi_to */
3858 cList
->u_prev
= NULL
;
3859 cList
->u_next
= hi_to
->channels
;
3860 if (hi_to
->channels
)
3861 hi_to
->channels
->u_prev
= cList
;
3862 hi_to
->channels
= cList
;
3866 /* Do they get an OpServ level promotion? */
3867 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3868 hi_to
->opserv_level
= hi_from
->opserv_level
;
3870 /* What about last seen time? */
3871 if (hi_from
->lastseen
> hi_to
->lastseen
)
3872 hi_to
->lastseen
= hi_from
->lastseen
;
3874 /* Does a fakehost carry over? (This intentionally doesn't set it
3875 * for users previously attached to hi_to. They'll just have to
3878 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3879 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3881 /* Notify of success. */
3882 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3883 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
3884 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3886 /* Unregister the "from" handle. */
3887 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3888 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
3889 * the process isn't completed.
3895 struct nickserv_discrim
{
3896 unsigned int limit
, min_level
, max_level
;
3897 unsigned long flags_on
, flags_off
;
3898 time_t min_registered
, max_registered
;
3900 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3901 const char *nickmask
;
3902 const char *hostmask
;
3903 const char *handlemask
;
3904 const char *emailmask
;
3906 unsigned int inldap
;
3910 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3912 struct discrim_apply_info
{
3913 struct nickserv_discrim
*discrim
;
3914 discrim_search_func func
;
3915 struct userNode
*source
;
3916 unsigned int matched
;
3919 static struct nickserv_discrim
*
3920 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
3923 struct nickserv_discrim
*discrim
;
3925 discrim
= malloc(sizeof(*discrim
));
3926 memset(discrim
, 0, sizeof(*discrim
));
3927 discrim
->min_level
= 0;
3928 discrim
->max_level
= ~0;
3929 discrim
->limit
= 50;
3930 discrim
->min_registered
= 0;
3931 discrim
->max_registered
= INT_MAX
;
3932 discrim
->lastseen
= now
;
3934 discrim
->inldap
= 2;
3937 for (i
=0; i
<argc
; i
++) {
3938 if (i
== argc
- 1) {
3939 reply("MSG_MISSING_PARAMS", argv
[i
]);
3942 if (!irccasecmp(argv
[i
], "limit")) {
3943 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3944 } else if (!irccasecmp(argv
[i
], "flags")) {
3945 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3946 } else if (!irccasecmp(argv
[i
], "registered")) {
3947 const char *cmp
= argv
[++i
];
3948 if (cmp
[0] == '<') {
3949 if (cmp
[1] == '=') {
3950 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3952 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3954 } else if (cmp
[0] == '=') {
3955 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3956 } else if (cmp
[0] == '>') {
3957 if (cmp
[1] == '=') {
3958 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3960 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3963 reply("MSG_INVALID_CRITERIA", cmp
);
3965 } else if (!irccasecmp(argv
[i
], "seen")) {
3966 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3967 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3968 discrim
->nickmask
= argv
[++i
];
3969 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3971 if (!irccasecmp(argv
[i
], "exact")) {
3972 if (i
== argc
- 1) {
3973 reply("MSG_MISSING_PARAMS", argv
[i
]);
3976 discrim
->hostmask_type
= EXACT
;
3977 } else if (!irccasecmp(argv
[i
], "subset")) {
3978 if (i
== argc
- 1) {
3979 reply("MSG_MISSING_PARAMS", argv
[i
]);
3982 discrim
->hostmask_type
= SUBSET
;
3983 } else if (!irccasecmp(argv
[i
], "superset")) {
3984 if (i
== argc
- 1) {
3985 reply("MSG_MISSING_PARAMS", argv
[i
]);
3988 discrim
->hostmask_type
= SUPERSET
;
3989 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3990 if (i
== argc
- 1) {
3991 reply("MSG_MISSING_PARAMS", argv
[i
]);
3994 discrim
->hostmask_type
= LASTQUIT
;
3997 discrim
->hostmask_type
= SUPERSET
;
3999 discrim
->hostmask
= argv
[++i
];
4000 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask") || !irccasecmp(argv
[i
], "account")) {
4001 if (!irccasecmp(argv
[++i
], "*")) {
4002 discrim
->handlemask
= 0;
4004 discrim
->handlemask
= argv
[i
];
4006 } else if (!irccasecmp(argv
[i
], "email")) {
4007 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
4008 reply("MSG_NO_SEARCH_ACCESS", "email");
4010 } else if (!irccasecmp(argv
[++i
], "*")) {
4011 discrim
->emailmask
= 0;
4013 discrim
->emailmask
= argv
[i
];
4015 } else if (!irccasecmp(argv
[i
], "access")) {
4016 const char *cmp
= argv
[++i
];
4017 if (cmp
[0] == '<') {
4018 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
4019 if (cmp
[1] == '=') {
4020 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
4022 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
4024 } else if (cmp
[0] == '=') {
4025 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
4026 } else if (cmp
[0] == '>') {
4027 if (cmp
[1] == '=') {
4028 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
4030 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
4033 reply("MSG_INVALID_CRITERIA", cmp
);
4036 } else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[i
], "inldap")) {
4038 if(true_string(argv
[i
])) {
4039 discrim
->inldap
= 1;
4041 else if (false_string(argv
[i
])) {
4042 discrim
->inldap
= 0;
4045 reply("MSG_INVALID_BINARY", argv
[i
]);
4049 reply("MSG_INVALID_CRITERIA", argv
[i
]);
4060 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
4062 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
4063 || (discrim
->flags_off
& hi
->flags
)
4064 || (discrim
->min_registered
> hi
->registered
)
4065 || (discrim
->max_registered
< hi
->registered
)
4066 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
4067 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
4068 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
4069 || (discrim
->min_level
> hi
->opserv_level
)
4070 || (discrim
->max_level
< hi
->opserv_level
)) {
4073 if (discrim
->hostmask
) {
4075 for (i
=0; i
<hi
->masks
->used
; i
++) {
4076 const char *mask
= hi
->masks
->list
[i
];
4077 if ((discrim
->hostmask_type
== SUBSET
)
4078 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
4079 else if ((discrim
->hostmask_type
== EXACT
)
4080 && !irccasecmp(discrim
->hostmask
, mask
)) break;
4081 else if ((discrim
->hostmask_type
== SUPERSET
)
4082 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
4083 else if ((discrim
->hostmask_type
== LASTQUIT
)
4084 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
4086 if (i
==hi
->masks
->used
) return 0;
4088 if (discrim
->nickmask
) {
4089 struct nick_info
*nick
= hi
->nicks
;
4091 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
4094 if (!nick
) return 0;
4097 if(nickserv_conf
.ldap_enable
&& discrim
->inldap
!= 2) {
4099 rc
= ldap_get_user_info(hi
->handle
, NULL
);
4100 if(discrim
->inldap
== 1 && rc
!= LDAP_SUCCESS
)
4102 if(discrim
->inldap
== 0 && rc
== LDAP_SUCCESS
)
4111 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
4113 dict_iterator_t it
, next
;
4114 unsigned int matched
;
4116 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
4117 it
&& (matched
< discrim
->limit
);
4119 next
= iter_next(it
);
4120 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
4121 dsf(source
, iter_data(it
));
4129 search_print_func(struct userNode
*source
, struct handle_info
*match
)
4131 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
4135 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
4140 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
4142 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
4143 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
4147 search_add2ldap_func (struct userNode
*source
, struct handle_info
*match
)
4151 if(match
->email_addr
&& match
->passwd
&& match
->handle
) {
4152 rc
= ldap_do_add(match
->handle
, match
->passwd
, match
->email_addr
);
4153 if(rc
!= LDAP_SUCCESS
) {
4154 send_message(source
, nickserv
, "NSMSG_LDAP_FAIL_ADD", match
->handle
, ldap_err2string(rc
));
4161 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
4163 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
4164 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
4165 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
4166 return hi_b
->opserv_level
- hi_a
->opserv_level
;
4167 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
4171 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
4173 struct handle_info_list hil
;
4174 struct helpfile_table tbl
;
4179 memset(&hil
, 0, sizeof(hil
));
4180 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
4181 struct handle_info
*hi
= iter_data(it
);
4182 if (hi
->opserv_level
)
4183 handle_info_list_append(&hil
, hi
);
4185 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
4186 tbl
.length
= hil
.used
+ 1;
4188 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
4189 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
4190 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4193 for (ii
= 0; ii
< hil
.used
; ) {
4194 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4195 ary
[0] = hil
.list
[ii
]->handle
;
4196 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
4197 tbl
.contents
[++ii
] = ary
;
4199 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4200 /*reply("MSG_MATCH_COUNT", hil.used); */
4201 for (ii
= 0; ii
< hil
.used
; ii
++)
4202 free(tbl
.contents
[ii
]);
4207 static NICKSERV_FUNC(cmd_search
)
4209 struct nickserv_discrim
*discrim
;
4210 discrim_search_func action
;
4211 struct svccmd
*subcmd
;
4212 unsigned int matches
;
4215 NICKSERV_MIN_PARMS(3);
4216 sprintf(buf
, "search %s", argv
[1]);
4217 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
4218 if (!irccasecmp(argv
[1], "print"))
4219 action
= search_print_func
;
4220 else if (!irccasecmp(argv
[1], "count"))
4221 action
= search_count_func
;
4222 else if (!irccasecmp(argv
[1], "unregister"))
4223 action
= search_unregister_func
;
4225 else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[1], "add2ldap"))
4226 action
= search_add2ldap_func
;
4229 reply("NSMSG_INVALID_ACTION", argv
[1]);
4233 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
4236 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
4240 if (action
== search_print_func
)
4241 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4242 else if (action
== search_count_func
)
4243 discrim
->limit
= INT_MAX
;
4245 matches
= nickserv_discrim_search(discrim
, action
, user
);
4248 reply("MSG_MATCH_COUNT", matches
);
4250 reply("MSG_NO_MATCHES");
4256 static MODCMD_FUNC(cmd_checkpass
)
4258 struct handle_info
*hi
;
4260 NICKSERV_MIN_PARMS(3);
4261 if (!(hi
= get_handle_info(argv
[1]))) {
4262 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
4265 if (checkpass(argv
[2], hi
->passwd
))
4266 reply("CHECKPASS_YES");
4268 reply("CHECKPASS_NO");
4274 nickserv_db_read_handle(char *handle
, dict_t obj
)
4277 struct string_list
*masks
, *slist
, *ignores
;
4278 struct handle_info
*hi
;
4279 struct userNode
*authed_users
;
4280 struct userData
*channels
;
4281 unsigned long int id
;
4284 char *setter
, *note
;
4287 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
4288 id
= str
? strtoul(str
, NULL
, 0) : 0;
4289 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
4291 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
4294 if ((hi
= get_handle_info(handle
))) {
4295 authed_users
= hi
->users
;
4296 channels
= hi
->channels
;
4298 hi
->channels
= NULL
;
4299 dict_remove(nickserv_handle_dict
, hi
->handle
);
4301 authed_users
= NULL
;
4304 if(nickserv_conf
.force_handles_lowercase
)
4305 irc_strtolower(handle
);
4306 hi
= register_handle(handle
, str
, id
);
4308 hi
->users
= authed_users
;
4309 while (authed_users
) {
4310 authed_users
->handle_info
= hi
;
4311 authed_users
= authed_users
->next_authed
;
4314 hi
->channels
= channels
;
4315 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
4316 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
4317 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
4318 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
4319 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
4320 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
4321 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
4322 hi
->language
= language_find(str
? str
: "C");
4323 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
4324 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
4325 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
4327 hi
->infoline
= strdup(str
);
4328 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
4329 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4330 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
4331 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
4332 /* We want to read the nicks even if disable_nicks is set. This is so
4333 * that we don't lose the nick data entirely. */
4334 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
4336 for (ii
=0; ii
<slist
->used
; ii
++)
4337 register_nick(slist
->list
[ii
], hi
);
4339 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
4341 for (ii
=0; str
[ii
]; ii
++)
4342 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
4344 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
4345 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4346 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
4347 hi
->announcements
= str
? str
[0] : '?';
4348 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
4349 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
4350 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
4351 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
4352 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
4354 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
4356 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
4357 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
4359 nickserv_set_email_addr(hi
, str
);
4360 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
4362 hi
->epithet
= strdup(str
);
4363 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
4365 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
4366 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
4367 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4368 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
4369 if (setter
&& date
&& note
)
4371 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
4376 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
4378 hi
->fakehost
= strdup(str
);
4380 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4382 const char *data
, *type
, *expires
, *cookie_str
;
4383 struct handle_cookie
*cookie
;
4385 cookie
= calloc(1, sizeof(*cookie
));
4386 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4387 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4388 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4389 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4390 if (!type
|| !expires
|| !cookie_str
) {
4391 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4394 if (!irccasecmp(type
, KEY_ACTIVATION
))
4395 cookie
->type
= ACTIVATION
;
4396 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4397 cookie
->type
= PASSWORD_CHANGE
;
4398 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4399 cookie
->type
= EMAIL_CHANGE
;
4400 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4401 cookie
->type
= ALLOWAUTH
;
4403 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4406 cookie
->expires
= strtoul(expires
, NULL
, 0);
4407 if (cookie
->expires
< now
)
4410 cookie
->data
= strdup(data
);
4411 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4415 nickserv_bake_cookie(cookie
);
4417 nickserv_free_cookie(cookie
);
4422 nickserv_saxdb_read(dict_t db
) {
4424 struct record_data
*rd
;
4427 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4429 handle
= strdup(iter_key(it
));
4430 nickserv_db_read_handle(handle
, rd
->d
.object
);
4436 static NICKSERV_FUNC(cmd_mergedb
)
4438 struct timeval start
, stop
;
4441 NICKSERV_MIN_PARMS(2);
4442 gettimeofday(&start
, NULL
);
4443 if (!(db
= parse_database(argv
[1]))) {
4444 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4447 nickserv_saxdb_read(db
);
4449 gettimeofday(&stop
, NULL
);
4450 stop
.tv_sec
-= start
.tv_sec
;
4451 stop
.tv_usec
-= start
.tv_usec
;
4452 if (stop
.tv_usec
< 0) {
4454 stop
.tv_usec
+= 1000000;
4456 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4461 expire_handles(UNUSED_ARG(void *data
))
4463 dict_iterator_t it
, next
;
4465 struct handle_info
*hi
;
4467 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4468 next
= iter_next(it
);
4470 if ((hi
->opserv_level
> 0)
4472 || HANDLE_FLAGGED(hi
, FROZEN
)
4473 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4476 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4477 if ((now
- hi
->lastseen
) > expiry
) {
4478 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4479 nickserv_unregister_handle(hi
, NULL
, NULL
);
4483 if (nickserv_conf
.handle_expire_frequency
)
4484 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4488 nickserv_load_dict(const char *fname
)
4492 if (!(file
= fopen(fname
, "r"))) {
4493 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4496 while (!feof(file
)) {
4497 fgets(line
, sizeof(line
), file
);
4500 if (line
[strlen(line
)-1] == '\n')
4501 line
[strlen(line
)-1] = 0;
4502 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4505 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4508 static enum reclaim_action
4509 reclaim_action_from_string(const char *str
) {
4511 return RECLAIM_NONE
;
4512 else if (!irccasecmp(str
, "warn"))
4513 return RECLAIM_WARN
;
4514 else if (!irccasecmp(str
, "svsnick"))
4515 return RECLAIM_SVSNICK
;
4516 else if (!irccasecmp(str
, "kill"))
4517 return RECLAIM_KILL
;
4519 return RECLAIM_NONE
;
4523 nickserv_conf_read(void)
4525 dict_t conf_node
, child
;
4528 struct string_list
*strlist
;
4530 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4531 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4534 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4536 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4537 if (nickserv_conf
.valid_handle_regex_set
)
4538 regfree(&nickserv_conf
.valid_handle_regex
);
4540 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4541 nickserv_conf
.valid_handle_regex_set
= !err
;
4542 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4544 nickserv_conf
.valid_handle_regex_set
= 0;
4546 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4547 if (nickserv_conf
.valid_nick_regex_set
)
4548 regfree(&nickserv_conf
.valid_nick_regex
);
4550 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4551 nickserv_conf
.valid_nick_regex_set
= !err
;
4552 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4554 nickserv_conf
.valid_nick_regex_set
= 0;
4556 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4557 if (nickserv_conf
.valid_fakehost_regex_set
)
4558 regfree(&nickserv_conf
.valid_fakehost_regex
);
4560 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4561 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4562 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4564 nickserv_conf
.valid_fakehost_regex_set
= 0;
4566 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4568 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4569 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4570 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4571 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4572 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4573 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4574 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4575 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4576 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4577 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4578 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4579 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4580 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4581 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4582 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4583 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4584 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4585 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4586 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4587 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4588 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4589 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4590 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4591 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4592 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4594 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4595 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4596 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4598 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4599 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4600 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4602 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4603 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4604 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4605 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4606 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4607 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4608 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4609 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4610 if (!nickserv_conf
.disable_nicks
) {
4611 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4612 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4613 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4614 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4615 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4616 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4617 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4618 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4620 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4621 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4622 const char *key
= iter_key(it
), *value
;
4626 if (!strncasecmp(key
, "uc_", 3))
4627 flag
= toupper(key
[3]);
4628 else if (!strncasecmp(key
, "lc_", 3))
4629 flag
= tolower(key
[3]);
4633 if ((pos
= handle_inverse_flags
[flag
])) {
4634 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4635 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4638 if (nickserv_conf
.weak_password_dict
)
4639 dict_delete(nickserv_conf
.weak_password_dict
);
4640 nickserv_conf
.weak_password_dict
= dict_new();
4641 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4642 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4643 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4644 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4646 nickserv_load_dict(str
);
4647 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4648 if (nickserv
&& str
)
4649 NickChange(nickserv
, str
, 0);
4650 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4651 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4652 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4653 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4654 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4655 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4656 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4657 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4658 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4659 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4660 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4661 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4662 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4663 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4664 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4665 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4666 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4667 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4668 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4669 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4671 free_string_list(nickserv_conf
.denied_fakehost_words
);
4672 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4674 strlist
= string_list_copy(strlist
);
4676 strlist
= alloc_string_list(4);
4677 string_list_append(strlist
, strdup("sex"));
4678 string_list_append(strlist
, strdup("fuck"));
4680 nickserv_conf
.denied_fakehost_words
= strlist
;
4682 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4683 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4685 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4686 nickserv_conf
.auto_oper
= str
? str
: "";
4688 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4689 nickserv_conf
.auto_admin
= str
? str
: "";
4691 str
= conf_get_data("server/network", RECDB_QSTRING
);
4692 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4693 if (!nickserv_conf
.auth_policer_params
) {
4694 nickserv_conf
.auth_policer_params
= policer_params_new();
4695 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4696 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4698 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4699 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4700 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4702 str
= database_get_data(conf_node
, KEY_LDAP_ENABLE
, RECDB_QSTRING
);
4703 nickserv_conf
.ldap_enable
= str
? strtoul(str
, NULL
, 0) : 0;
4705 str
= database_get_data(conf_node
, KEY_FORCE_HANDLES_LOWERCASE
, RECDB_QSTRING
);
4706 nickserv_conf
.force_handles_lowercase
= str
? strtol(str
, NULL
, 0) : 0;
4709 if(nickserv_conf
.ldap_enable
> 0) {
4710 /* ldap is enabled but not compiled in - error out */
4711 log_module(MAIN_LOG
, LOG_ERROR
, "ldap is enabled in config, but not compiled in!");
4712 nickserv_conf
.ldap_enable
= 0;
4718 str
= database_get_data(conf_node
, KEY_LDAP_URI
, RECDB_QSTRING
);
4719 nickserv_conf
.ldap_uri
= str
? str
: "";
4721 str
= database_get_data(conf_node
, KEY_LDAP_BASE
, RECDB_QSTRING
);
4722 nickserv_conf
.ldap_base
= str
? str
: "";
4724 str
= database_get_data(conf_node
, KEY_LDAP_DN_FMT
, RECDB_QSTRING
);
4725 nickserv_conf
.ldap_dn_fmt
= str
? str
: "";
4727 str
= database_get_data(conf_node
, KEY_LDAP_VERSION
, RECDB_QSTRING
);
4728 nickserv_conf
.ldap_version
= str
? strtoul(str
, NULL
, 0) : 3;
4730 str
= database_get_data(conf_node
, KEY_LDAP_AUTOCREATE
, RECDB_QSTRING
);
4731 nickserv_conf
.ldap_autocreate
= str
? strtoul(str
, NULL
, 0) : 0;
4733 str
= database_get_data(conf_node
, KEY_LDAP_TIMEOUT
, RECDB_QSTRING
);
4734 nickserv_conf
.ldap_timeout
= str
? strtoul(str
, NULL
, 0) : 5;
4736 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_DN
, RECDB_QSTRING
);
4737 nickserv_conf
.ldap_admin_dn
= str
? str
: "";
4739 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_PASS
, RECDB_QSTRING
);
4740 nickserv_conf
.ldap_admin_pass
= str
? str
: "";
4742 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_ACCOUNT
, RECDB_QSTRING
);
4743 nickserv_conf
.ldap_field_account
= str
? str
: "";
4745 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_PASSWORD
, RECDB_QSTRING
);
4746 nickserv_conf
.ldap_field_password
= str
? str
: "";
4748 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_EMAIL
, RECDB_QSTRING
);
4749 nickserv_conf
.ldap_field_email
= str
? str
: "";
4751 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_DN
, RECDB_QSTRING
);
4752 nickserv_conf
.ldap_oper_group_dn
= str
? str
: "";
4754 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_GROUP_MEMBER
, RECDB_QSTRING
);
4755 nickserv_conf
.ldap_field_group_member
= str
? str
: "";
4757 free_string_list(nickserv_conf
.ldap_object_classes
);
4758 strlist
= database_get_data(conf_node
, KEY_LDAP_OBJECT_CLASSES
, RECDB_STRING_LIST
);
4760 strlist
= string_list_copy(strlist
);
4762 strlist
= alloc_string_list(4);
4763 string_list_append(strlist
, strdup("top"));
4765 nickserv_conf
.ldap_object_classes
= strlist
;
4772 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4774 char newnick
[NICKLEN
+1];
4783 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4785 case RECLAIM_SVSNICK
:
4787 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4788 } while (GetUserH(newnick
));
4789 irc_svsnick(nickserv
, user
, newnick
);
4792 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4793 irc_kill(nickserv
, user
, msg
);
4799 nickserv_reclaim_p(void *data
) {
4800 struct userNode
*user
= data
;
4801 struct nick_info
*ni
= get_nick_info(user
->nick
);
4803 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4807 check_user_nick(struct userNode
*user
) {
4808 struct nick_info
*ni
;
4809 user
->modes
&= ~FLAGS_REGNICK
;
4810 if (!(ni
= get_nick_info(user
->nick
)))
4812 if (user
->handle_info
== ni
->owner
) {
4813 user
->modes
|= FLAGS_REGNICK
;
4817 if (nickserv_conf
.warn_nick_owned
)
4818 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4819 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4821 if (nickserv_conf
.auto_reclaim_delay
)
4822 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4824 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4829 handle_new_user(struct userNode
*user
)
4831 return check_user_nick(user
);
4835 handle_account(struct userNode
*user
, const char *stamp
)
4837 struct handle_info
*hi
;
4840 #ifdef WITH_PROTOCOL_P10
4841 time_t timestamp
= 0;
4843 colon
= strchr(stamp
, ':');
4844 if(colon
&& colon
[1])
4847 timestamp
= atoi(colon
+1);
4849 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4850 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4852 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
);
4856 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4857 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4861 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4864 set_user_handle_info(user
, hi
, 0);
4866 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4871 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4873 struct handle_info
*hi
;
4875 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4876 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4877 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4879 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4880 check_user_nick(user
);
4884 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4886 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4887 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4888 set_user_handle_info(user
, NULL
, 0);
4891 static struct modcmd
*
4892 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4894 if (min_level
> 0) {
4896 sprintf(buf
, "%u", min_level
);
4897 if (must_be_qualified
) {
4898 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4900 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4902 } else if (min_level
== 0) {
4903 if (must_be_qualified
) {
4904 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4906 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4909 if (must_be_qualified
) {
4910 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4912 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4918 nickserv_db_cleanup(void)
4920 unreg_del_user_func(nickserv_remove_user
);
4921 userList_clean(&curr_helpers
);
4922 policer_params_delete(nickserv_conf
.auth_policer_params
);
4923 dict_delete(nickserv_handle_dict
);
4924 dict_delete(nickserv_nick_dict
);
4925 dict_delete(nickserv_opt_dict
);
4926 dict_delete(nickserv_allow_auth_dict
);
4927 dict_delete(nickserv_email_dict
);
4928 dict_delete(nickserv_id_dict
);
4929 dict_delete(nickserv_conf
.weak_password_dict
);
4930 free(auth_func_list
);
4931 free(unreg_func_list
);
4933 free(allowauth_func_list
);
4934 free(handle_merge_func_list
);
4935 free(failpw_func_list
);
4936 if (nickserv_conf
.valid_handle_regex_set
)
4937 regfree(&nickserv_conf
.valid_handle_regex
);
4938 if (nickserv_conf
.valid_nick_regex_set
)
4939 regfree(&nickserv_conf
.valid_nick_regex
);
4943 init_nickserv(const char *nick
)
4945 struct chanNode
*chan
;
4947 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4948 reg_new_user_func(handle_new_user
);
4949 reg_nick_change_func(handle_nick_change
);
4950 reg_del_user_func(nickserv_remove_user
);
4951 reg_account_func(handle_account
);
4953 /* set up handle_inverse_flags */
4954 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4955 for (i
=0; handle_flags
[i
]; i
++) {
4956 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4957 flag_access_levels
[i
] = 0;
4960 conf_register_reload(nickserv_conf_read
);
4961 nickserv_opt_dict
= dict_new();
4962 nickserv_email_dict
= dict_new();
4964 dict_set_free_keys(nickserv_email_dict
, free
);
4965 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4967 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4968 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4969 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4970 * a big pain to disable since its nolonger in the config file. ) -Rubin
4972 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4973 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4974 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4975 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4976 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4977 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4978 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4979 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4980 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4981 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4982 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4983 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4984 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4985 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4986 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4987 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4988 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4989 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4990 if (!nickserv_conf
.disable_nicks
) {
4991 /* nick management commands */
4992 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4993 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4994 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4995 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4996 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4997 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4999 if (nickserv_conf
.email_enabled
) {
5000 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
5001 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
5002 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
5003 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
5004 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
5005 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
5007 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
5008 /* ignore commands */
5009 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
5010 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
5011 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
5012 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
5013 /* miscellaneous commands */
5014 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
5015 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
5016 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
5017 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
5018 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
5020 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
5021 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
5022 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
5023 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
5024 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
5025 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
5026 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
5027 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
5028 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
5029 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
5030 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
5031 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
5032 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
5033 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
5034 if (nickserv_conf
.titlehost_suffix
) {
5035 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
5036 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
5038 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
5039 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
5040 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
5041 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
5043 nickserv_handle_dict
= dict_new();
5044 dict_set_free_keys(nickserv_handle_dict
, free
);
5045 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
5047 nickserv_id_dict
= dict_new();
5048 dict_set_free_keys(nickserv_id_dict
, free
);
5050 nickserv_nick_dict
= dict_new();
5051 dict_set_free_data(nickserv_nick_dict
, free
);
5053 nickserv_allow_auth_dict
= dict_new();
5055 userList_init(&curr_helpers
);
5058 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
5059 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
5060 nickserv_service
= service_register(nickserv
);
5062 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
5063 reg_exit_func(nickserv_db_cleanup
);
5064 if(nickserv_conf
.handle_expire_frequency
)
5065 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
5067 if(autojoin_channels
&& nickserv
) {
5068 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
5069 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
5070 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
5074 ldap_do_init(nickserv_conf
);
5077 message_register_table(msgtab
);