1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
33 #include <tre/regex.h>
39 #define NICKSERV_CONF_NAME "services/nickserv"
41 #define KEY_DISABLE_NICKS "disable_nicks"
42 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
43 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
44 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
45 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
46 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
47 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
48 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
49 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
50 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
51 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
52 #define KEY_VALID_FAKEHOST_REGEX "valid_fakehost_regex"
53 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
54 #define KEY_MODOPER_LEVEL "modoper_level"
55 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
56 #define KEY_SET_TITLE_LEVEL "set_title_level"
57 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
58 #define KEY_DENIED_FAKEHOST_WORDS "denied_fakehost_words"
59 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
60 #define KEY_AUTO_OPER "auto_oper"
61 #define KEY_AUTO_ADMIN "auto_admin"
62 #define KEY_AUTO_OPER_PRIVS "auto_oper_privs"
63 #define KEY_AUTO_ADMIN_PRIVS "auto_admin_privs"
64 #define KEY_FLAG_LEVELS "flag_levels"
65 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
66 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
67 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
68 #define KEY_NICK_EXPIRE_FREQ "nick_expire_freq"
69 #define KEY_NICK_EXPIRE_DELAY "nick_expire_delay"
70 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
71 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
72 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
73 #define KEY_DICT_FILE "dict_file"
74 #define KEY_NICK "nick"
75 #define KEY_LANGUAGE "language"
76 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
77 #define KEY_AUTOGAG_DURATION "autogag_duration"
78 #define KEY_AUTH_POLICER "auth_policer"
79 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
80 #define KEY_EMAIL_ENABLED "email_enabled"
81 #define KEY_EMAIL_REQUIRED "email_required"
82 #define KEY_SYNC_LOG "sync_log"
83 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
84 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
85 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
86 #define KEY_DEFAULT_STYLE "default_style"
87 #define KEY_OUNREGISTER_INACTIVE "ounregister_inactive"
88 #define KEY_OUNREGISTER_FLAGS "ounregister_flags"
91 #define KEY_PASSWD "passwd"
92 #define KEY_NICKS "nicks"
93 #define KEY_NICKS_EX "nicks_ex"
94 #define KEY_MASKS "masks"
95 #define KEY_SSLFPS "sslfps"
96 #define KEY_IGNORES "ignores"
97 #define KEY_OPSERV_LEVEL "opserv_level"
98 #define KEY_FLAGS "flags"
99 #define KEY_REGISTER_ON "register"
100 #define KEY_LAST_SEEN "lastseen"
101 #define KEY_INFO "info"
102 #define KEY_USERLIST_STYLE "user_style"
103 #define KEY_SCREEN_WIDTH "screen_width"
104 #define KEY_LAST_AUTHED_HOST "last_authed_host"
105 #define KEY_LAST_QUIT_HOST "last_quit_host"
106 #define KEY_EMAIL_ADDR "email_addr"
107 #define KEY_COOKIE "cookie"
108 #define KEY_COOKIE_DATA "data"
109 #define KEY_COOKIE_TYPE "type"
110 #define KEY_COOKIE_EXPIRES "expires"
111 #define KEY_ACTIVATION "activation"
112 #define KEY_PASSWORD_CHANGE "password change"
113 #define KEY_EMAIL_CHANGE "email change"
114 #define KEY_ALLOWAUTH "allowauth"
115 #define KEY_EPITHET "epithet"
116 #define KEY_TABLE_WIDTH "table_width"
117 #define KEY_ANNOUNCEMENTS "announcements"
118 #define KEY_MAXLOGINS "maxlogins"
119 #define KEY_FAKEHOST "fakehost"
120 #define KEY_NOTE_NOTE "note"
121 #define KEY_NOTE_SETTER "setter"
122 #define KEY_NOTE_DATE "date"
123 #define KEY_KARMA "karma"
124 #define KEY_FORCE_HANDLES_LOWERCASE "force_handles_lowercase"
126 #define KEY_LDAP_ENABLE "ldap_enable"
129 #define KEY_LDAP_URI "ldap_uri"
130 #define KEY_LDAP_BASE "ldap_base"
131 #define KEY_LDAP_DN_FMT "ldap_dn_fmt"
132 #define KEY_LDAP_VERSION "ldap_version"
133 #define KEY_LDAP_AUTOCREATE "ldap_autocreate"
134 #define KEY_LDAP_ADMIN_DN "ldap_admin_dn"
135 #define KEY_LDAP_ADMIN_PASS "ldap_admin_pass"
136 #define KEY_LDAP_FIELD_ACCOUNT "ldap_field_account"
137 #define KEY_LDAP_FIELD_PASSWORD "ldap_field_password"
138 #define KEY_LDAP_FIELD_EMAIL "ldap_field_email"
139 #define KEY_LDAP_FIELD_OSLEVEL "ldap_field_oslevel"
140 #define KEY_LDAP_OBJECT_CLASSES "ldap_object_classes"
141 #define KEY_LDAP_OPER_GROUP_DN "ldap_oper_group_dn"
142 #define KEY_LDAP_OPER_GROUP_LEVEL "ldap_oper_group_level"
143 #define KEY_LDAP_FIELD_GROUP_MEMBER "ldap_field_group_member"
144 #define KEY_LDAP_TIMEOUT "ldap_timeout"
147 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
149 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
150 #define OPTION_FUNC(NAME) int NAME(UNUSED_ARG(struct svccmd *cmd), struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), int noreply, unsigned int argc, char *argv[])
151 typedef OPTION_FUNC(option_func_t
);
153 DEFINE_LIST(handle_info_list
, struct handle_info
*)
155 #define NICKSERV_MIN_PARMS(N) do { \
157 reply("MSG_MISSING_PARAMS", argv[0]); \
158 svccmd_send_help_brief(user, nickserv, cmd); \
162 struct userNode
*nickserv
;
163 struct userList curr_helpers
;
164 const char *handle_flags
= HANDLE_FLAGS
;
166 extern struct string_list
*autojoin_channels
;
167 static struct module *nickserv_module
;
168 static struct service
*nickserv_service
;
169 static struct log_type
*NS_LOG
;
170 dict_t nickserv_handle_dict
; /* contains struct handle_info* */
171 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
172 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
173 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
174 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
175 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
176 static char handle_inverse_flags
[256];
177 static unsigned int flag_access_levels
[32];
178 static const struct message_entry msgtab
[] = {
179 { "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." },
180 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
181 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu characters or less."},
182 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
183 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
184 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
185 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
186 { "NSMSG_LDAP_FAIL", "There was a problem in contacting the account server (ldap): %s. Please try again later." },
187 { "NSMSG_LDAP_FAIL_ADD", "There was a problem in adding account %s to ldap: %s." },
188 { "NSMSG_LDAP_FAIL_SEND_EMAIL", "There was a problem in storing your email address in the account server (ldap): %s. Please try again later." },
189 { "NSMSG_LDAP_FAIL_GET_EMAIL", "There was a problem in retrieving your email address from the account server (ldap): %s. Please try again later." },
190 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
191 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
192 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
193 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
194 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
195 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
196 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
197 { "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." },
198 { "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." },
199 { "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." },
200 { "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." },
201 { "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." },
202 { "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." },
203 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
204 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
205 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
206 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
207 { "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." },
208 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
209 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
210 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
211 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
212 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
213 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
214 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
215 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
216 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
217 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
218 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
219 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
220 { "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 *@*)." },
221 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
222 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
223 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
224 { "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 $N authcookie %1$s)" },
225 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
226 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
227 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
228 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
229 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
230 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
231 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
232 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
233 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
234 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
235 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
236 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
237 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
238 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
239 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
240 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
241 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
242 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
243 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
244 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
245 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
246 { "NSMSG_HANDLEINFO_KARMA", "Karma: %d" },
247 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
248 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
249 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
250 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
251 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
252 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
253 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
254 { "NSMSG_HANDLEINFO_COOKIE_EMAIL_DATA", "Cookie: New email address: %s" },
255 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
256 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
257 { "NSMSG_HANDLEINFO_OPSERV_LEVEL", "Opserv level: %d " },
258 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
259 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
260 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
261 { "NSMSG_INVALID_KARMA", "$b%s$b is not a valid karma modifier." },
262 { "NSMSG_SET_KARMA", "$bKARMA: $b%d$b" },
263 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
264 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
265 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
266 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
267 { "NSMSG_HANDLEINFO_SSLFPS", "Client Certificate Fingerprints(s): %s" },
268 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
269 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
270 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
271 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
272 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
273 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
274 { "NSMSG_NICKINFO_ON", "$bNick Information for %s$b" },
275 { "NSMSG_NICKINFO_END", "----------End of Nick Info-----------" },
276 { "NSMSG_NICKINFO_REGGED", "Registered on: %s" },
277 { "NSMSG_NICKINFO_LASTSEEN", "Last seen: %s" },
278 { "NSMSG_NICKINFO_LASTSEEN_NOW", "Last seen: Right now!" },
279 { "NSMSG_NICKINFO_OWNER", "Account: %s." },
280 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
281 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
282 { "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)." },
283 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
284 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
285 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
286 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
287 { "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." },
288 { "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." },
289 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
290 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
291 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
292 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
293 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
294 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
295 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
296 { "NSMSG_PASS_SUCCESS", "Password changed." },
297 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
298 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
299 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
300 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
301 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
302 { "NSMSG_ADDSSLFP_ALREADY", "$b%s$b is already a client certificate fingerprint in your account." },
303 { "NSMSG_ADDSSLFP_SUCCESS", "Client certificate fingerprint %s added." },
304 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
305 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
306 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
307 { "NSMSG_DELSSLFP_SUCCESS", "Client certificate fingerprint %s deleted." },
308 { "NSMSG_DELSSLFP_NOT_FOUND", "Unable to find client certificate fingerprint to be deleted." },
309 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
310 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
311 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
312 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
313 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
314 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
315 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
316 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
317 { "NSMSG_UNREGISTER_MUST_FORCE", "Account $b%s$b is not inactive or has special flags set; use FORCE to unregister it." },
318 { "NSMSG_UNREGISTER_CANNOT_FORCE", "Account $b%s$b is not inactive or has special flags set; have an IRCOp use FORCE to unregister it." },
319 { "NSMSG_UNREGISTER_NODELETE", "Account $b%s$b is protected from unregistration." },
320 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
321 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
322 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
323 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
324 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
325 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
326 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
327 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
328 { "NSMSG_NO_ACCESS", "Access denied." },
329 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
330 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
331 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
332 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
333 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
334 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
335 { "NSMSG_BAD_HANDLE", "Account $b%s$b is not allowed because it is reserved, is too long, or contains invalid characters." },
336 { "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." },
337 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
338 { "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." },
339 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
340 { "NSMSG_SEARCH_MATCH", "Match: %s" },
341 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
342 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
343 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
344 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
345 { "NSMSG_RECLAIM_HOWTO", "To auth to account %s you must use /msg %s@%s AUTH %s <password>" },
346 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
347 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
348 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
349 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
350 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
351 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
352 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
353 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
354 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
355 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
356 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
357 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
358 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
359 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
360 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
361 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
362 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
363 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
364 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
365 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
366 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
367 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
368 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
369 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
370 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
371 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
372 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
373 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
374 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
375 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
377 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
378 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
380 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
381 { "NSEMAIL_ACTIVATION_BODY",
382 "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"
384 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
385 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
386 "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"
387 "/msg %3$s@%4$s AUTH %5$s your-password\n"
388 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
389 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
391 "If you did NOT request this account, you do not need to do anything.\n"
392 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
393 { "NSEMAIL_ACTIVATION_BODY_WEB",
394 "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"
396 "To verify your email address and complete the account registration, visit the following URL:\n"
397 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
399 "If you did NOT request this account, you do not need to do anything.\n"
400 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
401 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
402 { "NSEMAIL_PASSWORD_CHANGE_BODY",
403 "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"
404 "To complete the password change, log on to %1$s and type the following command:\n"
405 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
406 "If you did NOT request your password to be changed, you do not need to do anything.\n"
407 "Please contact the %1$s staff if you have questions." },
408 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
409 "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"
410 "To complete the password change, click the following URL:\n"
411 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
412 "If you did NOT request your password to be changed, you do not need to do anything.\n"
413 "Please contact the %1$s staff if you have questions." },
414 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
415 #ifdef stupid_verify_old_email
416 { "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." },
417 { "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." },
419 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
420 { "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." },
421 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
422 { "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." },
423 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
424 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
425 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
426 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
427 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
428 { "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." },
429 { "CHECKPASS_YES", "Yes." },
430 { "CHECKPASS_NO", "No." },
431 { "CHECKEMAIL_NOT_SET", "No email set." },
432 { "CHECKEMAIL_YES", "Yes." },
433 { "CHECKEMAIL_NO", "No." },
434 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
438 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
439 static void nickserv_reclaim_p(void *data
);
440 static int nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
);
442 struct nickserv_config nickserv_conf
;
444 /* We have 2^32 unique account IDs to use. */
445 unsigned long int highest_id
= 0;
448 canonicalize_hostmask(char *mask
)
450 char *out
= mask
, *temp
;
451 if ((temp
= strchr(mask
, '!'))) {
453 while (*temp
) *out
++ = *temp
++;
459 static struct handle_note
*
460 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
462 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
464 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
466 memcpy(note
->note
, text
, strlen(text
));
470 static struct handle_info
*
471 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
473 struct handle_info
*hi
;
475 hi
= calloc(1, sizeof(*hi
));
476 hi
->userlist_style
= nickserv_conf
.default_style
? nickserv_conf
.default_style
: HI_DEFAULT_STYLE
;
477 hi
->announcements
= '?';
478 hi
->handle
= strdup(handle
);
479 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
481 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
487 register_nick(const char *nick
, struct handle_info
*owner
)
489 struct nick_info
*ni
;
490 ni
= malloc(sizeof(struct nick_info
));
491 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
492 ni
->registered
= now
;
495 ni
->next
= owner
->nicks
;
497 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
501 delete_nick(struct nick_info
*ni
)
503 struct nick_info
*last
, *next
;
504 struct userNode
*user
;
505 /* Check to see if we should mark a user as unregistered. */
506 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
507 user
->modes
&= ~FLAGS_REGNICK
;
510 /* Remove ni from the nick_info linked list. */
511 if (ni
== ni
->owner
->nicks
) {
512 ni
->owner
->nicks
= ni
->next
;
514 last
= ni
->owner
->nicks
;
520 last
->next
= next
->next
;
522 dict_remove(nickserv_nick_dict
, ni
->nick
);
525 static unreg_func_t
*unreg_func_list
;
526 static void **unreg_func_list_extra
;
527 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
530 reg_unreg_func(unreg_func_t func
, void *extra
)
532 if (unreg_func_used
== unreg_func_size
) {
533 if (unreg_func_size
) {
534 unreg_func_size
<<= 1;
535 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
536 unreg_func_list_extra
= realloc(unreg_func_list_extra
, unreg_func_size
*sizeof(void*));
539 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
540 unreg_func_list_extra
= malloc(unreg_func_size
*sizeof(void*));
543 unreg_func_list
[unreg_func_used
] = func
;
544 unreg_func_list_extra
[unreg_func_used
++] = extra
;
548 nickserv_free_cookie(void *data
)
550 struct handle_cookie
*cookie
= data
;
551 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
552 if (cookie
->data
) free(cookie
->data
);
557 free_handle_info(void *vhi
)
559 struct handle_info
*hi
= vhi
;
561 free_string_list(hi
->masks
);
562 free_string_list(hi
->sslfps
);
563 free_string_list(hi
->ignores
);
567 delete_nick(hi
->nicks
);
573 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
574 nickserv_free_cookie(hi
->cookie
);
576 if (hi
->email_addr
) {
577 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
578 handle_info_list_remove(hil
, hi
);
580 dict_remove(nickserv_email_dict
, hi
->email_addr
);
585 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
588 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
591 struct userNode
*uNode
;
594 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
596 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
597 if( (rc
= ldap_delete_account(hi
->handle
)) != LDAP_SUCCESS
) {
599 send_message(notify
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
601 if(rc
!= LDAP_NO_SUCH_OBJECT
)
602 return false; /* if theres noone there to delete, its kinda ok, right ?:) */
607 for (n
=0; n
<unreg_func_used
; n
++)
608 unreg_func_list
[n
](notify
, hi
, unreg_func_list_extra
[n
]);
610 if (nickserv_conf
.sync_log
) {
611 uNode
= GetUserH(hi
->users
->nick
);
615 set_user_handle_info(hi
->users
, NULL
, 0);
618 if (nickserv_conf
.disable_nicks
)
619 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
621 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
624 if (nickserv_conf
.sync_log
)
625 SyncLog("UNREGISTER %s", hi
->handle
);
627 dict_remove(nickserv_handle_dict
, hi
->handle
);
632 get_handle_info(const char *handle
)
634 return dict_find(nickserv_handle_dict
, handle
, 0);
638 get_nick_info(const char *nick
)
640 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
644 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
649 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
650 mn
= channel
->members
.list
[nn
];
651 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
658 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
659 if (!user
->handle_info
) {
661 send_message(user
, bot
, "MSG_AUTHENTICATE");
665 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
667 send_message(user
, bot
, "NSMSG_NO_ACCESS");
671 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
673 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
677 if (user
->handle_info
->opserv_level
< min_level
) {
679 send_message(user
, bot
, "NSMSG_NO_ACCESS");
687 is_valid_handle(const char *handle
)
689 struct userNode
*user
;
690 /* cant register a juped nick/service nick as handle, to prevent confusion */
691 user
= GetUserH(handle
);
692 if (user
&& IsLocal(user
))
694 /* check against maximum length */
695 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
697 /* for consistency, only allow account names that could be nicks */
698 if (!is_valid_nick(handle
))
700 /* disallow account names that look like bad words */
701 if (opserv_bad_channel(handle
))
703 /* test either regex or containing all valid chars */
704 if (nickserv_conf
.valid_handle_regex_set
) {
705 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
708 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
709 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
713 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
718 is_registerable_nick(const char *nick
)
720 struct userNode
*user
;
721 /* cant register a juped nick/service nick as nick, to prevent confusion */
722 user
= GetUserH(nick
);
723 if (user
&& IsLocal(user
))
725 /* for consistency, only allow nicks names that could be nicks */
726 if (!is_valid_nick(nick
))
728 /* disallow nicks that look like bad words */
729 if (opserv_bad_channel(nick
))
732 if (strlen(nick
) > NICKLEN
)
734 /* test either regex or as valid handle */
735 if (nickserv_conf
.valid_nick_regex_set
) {
736 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
739 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
740 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
746 /* this has been replaced with one in tools.c
749 is_valid_email_addr(const char *email)
751 return strchr(email, '@') != NULL;
757 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
759 if (hi
->email_addr
) {
760 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
761 return hi
->email_addr
;
771 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
773 struct handle_info
*hi
;
774 struct userNode
*target
;
778 if (!(hi
= get_handle_info(++name
))) {
779 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
784 if (!(target
= GetUserH(name
))) {
785 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
788 if (IsLocal(target
)) {
789 if (IsService(target
))
790 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
792 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
795 if (!(hi
= target
->handle_info
)) {
796 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
804 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
805 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
807 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
808 if ((user
->handle_info
->opserv_level
== 1000)
809 || (user
->handle_info
== hi
)
810 || ((user
->handle_info
->opserv_level
== 0)
811 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
812 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
816 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
821 get_victim_oper(struct userNode
*user
, const char *target
)
823 struct handle_info
*hi
;
824 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
826 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
827 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
830 return oper_outranks(user
, hi
) ? hi
: NULL
;
834 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
838 /* If no hostmasks on the account, allow it. */
839 if (!hi
->masks
->used
)
841 /* If any hostmask matches, allow it. */
842 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
843 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0, 0))
845 /* If they are allowauthed to this account, allow it (removing the aa). */
846 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
847 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
850 /* The user is not allowed to use this account. */
855 valid_user_sslfp(struct userNode
*user
, struct handle_info
*hi
)
859 if (!hi
->sslfps
->used
)
864 /* If any SSL fingerprint matches, allow it. */
865 for (ii
=0; ii
<hi
->sslfps
->used
; ii
++)
866 if (!irccasecmp(user
->sslfp
, hi
->sslfps
->list
[ii
]))
869 /* No valid SSL fingerprint found. */
874 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
877 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
881 if (len
< nickserv_conf
.password_min_length
) {
883 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
886 if (!irccasecmp(pass
, handle
)) {
888 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
891 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
894 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
897 for (i
=0; i
<len
; i
++) {
898 if (isdigit(pass
[i
]))
900 if (isupper(pass
[i
]))
902 if (islower(pass
[i
]))
905 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
906 || (cnt_upper
< nickserv_conf
.password_min_upper
)
907 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
909 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
915 static auth_func_t
*auth_func_list
;
916 static void **auth_func_list_extra
;
917 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
920 reg_auth_func(auth_func_t func
, void *extra
)
922 if (auth_func_used
== auth_func_size
) {
923 if (auth_func_size
) {
924 auth_func_size
<<= 1;
925 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
926 auth_func_list_extra
= realloc(auth_func_list_extra
, auth_func_size
*sizeof(void*));
929 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
930 auth_func_list_extra
= malloc(auth_func_size
*sizeof(void*));
933 auth_func_list
[auth_func_used
] = func
;
934 auth_func_list_extra
[auth_func_used
++] = extra
;
937 static handle_rename_func_t
*rf_list
;
938 static void **rf_list_extra
;
939 static unsigned int rf_list_size
, rf_list_used
;
942 reg_handle_rename_func(handle_rename_func_t func
, void *extra
)
944 if (rf_list_used
== rf_list_size
) {
947 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
948 rf_list_extra
= realloc(rf_list_extra
, rf_list_size
*sizeof(void*));
951 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
952 rf_list_extra
= malloc(rf_list_size
*sizeof(void*));
955 rf_list
[rf_list_used
] = func
;
956 rf_list_extra
[rf_list_used
++] = extra
;
960 generate_fakehost(struct handle_info
*handle
)
962 struct userNode
*target
;
963 extern const char *hidden_host_suffix
;
964 static char buffer
[HOSTLEN
+1];
968 if (!handle
->fakehost
) {
969 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
973 if ((style
== 1) || (style
== 3))
974 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
975 else if (style
== 2) {
976 /* Due to the way fakehost is coded theres no way i can
977 get the exact user, so for now ill just take the first
979 for (target
= handle
->users
; target
; target
= target
->next_authed
)
983 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
985 strncpy(buffer
, "none", sizeof(buffer
));
988 } else if (handle
->fakehost
[0] == '.') {
989 /* A leading dot indicates the stored value is actually a title. */
990 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
993 return handle
->fakehost
;
997 apply_fakehost(struct handle_info
*handle
)
999 struct userNode
*target
;
1004 fake
= generate_fakehost(handle
);
1005 for (target
= handle
->users
; target
; target
= target
->next_authed
)
1006 assign_fakehost(target
, fake
, 1);
1009 void send_func_list(struct userNode
*user
)
1012 struct handle_info
*old_info
;
1014 old_info
= user
->handle_info
;
1016 for (n
=0; n
<auth_func_used
; n
++)
1017 auth_func_list
[n
](user
, old_info
, auth_func_list_extra
[n
]);
1021 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
1024 struct handle_info
*old_info
;
1026 /* This can happen if somebody uses COOKIE while authed, or if
1027 * they re-auth to their current handle (which is silly, but users
1028 * are like that). */
1029 if (user
->handle_info
== hi
)
1032 if (user
->handle_info
) {
1033 struct userNode
*other
;
1034 struct nick_info
* ni
;
1037 userList_remove(&curr_helpers
, user
);
1039 /* remove from next_authed linked list */
1040 if (user
->handle_info
->users
== user
) {
1041 user
->handle_info
->users
= user
->next_authed
;
1042 } else if (user
->handle_info
->users
!= NULL
) {
1043 for (other
= user
->handle_info
->users
;
1044 other
->next_authed
!= user
;
1045 other
= other
->next_authed
) ;
1046 other
->next_authed
= user
->next_authed
;
1048 /* No users authed to the account - can happen if they get
1049 * killed for authing. */
1051 /* if nobody left on old handle, and they're not an oper, remove !god */
1052 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
1053 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
1054 /* record them as being last seen at this time */
1055 user
->handle_info
->lastseen
= now
;
1056 if ((ni
= get_nick_info(user
->nick
)))
1058 /* and record their hostmask */
1059 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
1061 old_info
= user
->handle_info
;
1062 user
->handle_info
= hi
;
1063 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1064 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1066 /* Call auth handlers */
1067 if (!GetUserH(user
->nick
))
1071 struct nick_info
*ni
;
1073 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1074 if (nickserv_conf
.warn_clone_auth
) {
1075 struct userNode
*other
;
1076 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1077 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1080 /* Add this auth to users list of current auths */
1081 user
->next_authed
= hi
->users
;
1084 /* Add to helpers list */
1085 if (IsHelper(user
) && !userList_contains(&curr_helpers
, user
))
1086 userList_append(&curr_helpers
, user
);
1088 /* Set the fakehost */
1089 if (hi
->fakehost
|| old_info
)
1093 #ifdef WITH_PROTOCOL_P10
1094 /* Stamp users with their account name. */
1095 char *id
= hi
->handle
;
1097 const char *id
= "???";
1099 /* Mark all the nicks registered to this
1100 * account as registered nicks
1101 * - Why not just this one? -rubin */
1102 if (!nickserv_conf
.disable_nicks
) {
1103 struct nick_info
*ni2
;
1104 for (ni2
= hi
->nicks
; ni2
; ni2
= ni2
->next
) {
1105 if (!irccasecmp(user
->nick
, ni2
->nick
)) {
1106 user
->modes
|= FLAGS_REGNICK
;
1111 /* send the account to the ircd */
1112 StampUser(user
, id
, hi
->registered
);
1115 /* Stop trying to kick this user off their nick */
1116 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
)) {
1117 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1121 /* We cannot clear the user's account ID, unfortunately. */
1122 user
->next_authed
= NULL
;
1125 /* Call auth handlers */
1126 if (GetUserH(user
->nick
)) {
1127 for (n
=0; n
<auth_func_used
; n
++) {
1128 auth_func_list
[n
](user
, old_info
, auth_func_list_extra
[n
]);
1135 static struct handle_info
*
1136 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1138 struct handle_info
*hi
;
1139 struct nick_info
*ni
;
1140 char crypted
[MD5_CRYPT_LENGTH
] = "";
1142 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1144 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1148 if(strlen(handle
) > 30)
1151 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 30);
1157 if (!is_secure_password(handle
, passwd
, user
))
1160 cryptpass(passwd
, crypted
);
1163 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1165 rc
= ldap_do_add(handle
, (no_auth
|| !passwd
? NULL
: crypted
), NULL
);
1166 if(LDAP_SUCCESS
!= rc
&& LDAP_ALREADY_EXISTS
!= rc
) {
1168 send_message(user
, nickserv
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1173 hi
= register_handle(handle
, crypted
, 0);
1174 hi
->masks
= alloc_string_list(1);
1175 hi
->sslfps
= alloc_string_list(1);
1176 hi
->ignores
= alloc_string_list(1);
1178 hi
->language
= lang_C
;
1179 hi
->registered
= now
;
1181 hi
->flags
= HI_DEFAULT_FLAGS
;
1182 if (settee
&& !no_auth
)
1183 set_user_handle_info(settee
, hi
, 1);
1185 if (user
!= settee
) {
1187 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1189 else if (nickserv_conf
.disable_nicks
) {
1191 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1194 else if (user
&& (ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
))) {
1196 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1201 if (is_registerable_nick(user
->nick
)) {
1202 register_nick(user
->nick
, hi
);
1203 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1207 if (is_registerable_nick(handle
)) {
1208 register_nick(handle
, hi
);
1212 if (settee
&& (user
!= settee
)) {
1214 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1221 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1223 cookie
->hi
->cookie
= cookie
;
1224 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1227 /* Contributed by the great sneep of afternet ;) */
1228 /* Since this gets used in a URL, we want to avoid stuff that confuses
1229 * email clients such as ] and ?. a-z, 0-9 only.
1231 void genpass(char *str
, int len
)
1236 for(i
= 0; i
< len
; i
++)
1240 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1241 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1249 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1251 struct handle_cookie
*cookie
;
1252 char subject
[128], body
[4096], *misc
;
1253 const char *netname
, *fmt
;
1257 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1261 cookie
= calloc(1, sizeof(*cookie
));
1263 cookie
->type
= type
;
1264 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1266 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1267 /* Adding dedicated password gen function for more control -Rubin */
1268 genpass(cookie
->cookie
, 10);
1270 *inttobase64(cookie->cookie, rand(), 5);
1271 *inttobase64(cookie->cookie+5, rand(), 5);
1274 netname
= nickserv_conf
.network_name
;
1277 switch (cookie
->type
) {
1279 hi
->passwd
[0] = 0; /* invalidate password */
1280 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1281 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1282 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1285 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1287 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1289 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1292 case PASSWORD_CHANGE
:
1293 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1294 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1295 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1297 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1299 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1300 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1304 misc
= hi
->email_addr
;
1305 hi
->email_addr
= cookie
->data
;
1306 #ifdef stupid_verify_old_email
1308 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1309 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1310 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1311 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1312 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1313 mail_send(nickserv
, hi
, subject
, body
, 1);
1314 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1315 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1319 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1320 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1321 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1322 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1323 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1324 mail_send(nickserv
, hi
, subject
, body
, 1);
1326 #ifdef stupid_verify_old_email
1329 hi
->email_addr
= misc
;
1332 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1333 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1334 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1335 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1336 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1339 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1343 mail_send(nickserv
, hi
, subject
, body
, first_time
);
1344 nickserv_bake_cookie(cookie
);
1348 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1350 cookie
->hi
->cookie
= NULL
;
1351 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1352 nickserv_free_cookie(cookie
);
1356 nickserv_free_email_addr(void *data
)
1358 handle_info_list_clean(data
);
1363 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1365 struct handle_info_list
*hil
;
1366 /* Remove from old handle_info_list ... */
1367 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1368 handle_info_list_remove(hil
, hi
);
1369 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1370 hi
->email_addr
= NULL
;
1372 /* Add to the new list.. */
1373 if (new_email_addr
) {
1374 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1375 hil
= calloc(1, sizeof(*hil
));
1376 hil
->tag
= strdup(new_email_addr
);
1377 handle_info_list_init(hil
);
1378 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1380 handle_info_list_append(hil
, hi
);
1381 hi
->email_addr
= hil
->tag
;
1385 static NICKSERV_FUNC(cmd_register
)
1388 struct handle_info
*hi
;
1389 const char *email_addr
, *password
;
1390 char syncpass
[MD5_CRYPT_LENGTH
];
1391 int no_auth
, weblink
;
1393 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1394 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1398 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1399 /* Require the first handle registered to belong to someone +o. */
1400 reply("NSMSG_REQUIRE_OPER");
1404 if (user
->handle_info
) {
1405 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1409 if (IsRegistering(user
)) {
1410 reply("NSMSG_ALREADY_REGISTERING");
1414 if (IsStamped(user
)) {
1415 /* Unauthenticated users might still have been stamped
1416 previously and could therefore have a hidden host;
1417 do not allow them to register a new account. */
1418 reply("NSMSG_STAMPED_REGISTER");
1422 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1424 if(nickserv_conf
.force_handles_lowercase
)
1425 irc_strtolower(argv
[1]);
1426 if (!is_valid_handle(argv
[1])) {
1427 reply("NSMSG_BAD_HANDLE", argv
[1]);
1432 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1433 struct handle_info_list
*hil
;
1436 /* Remember email address. */
1437 email_addr
= argv
[3];
1439 /* Check that the email address looks valid.. */
1440 if (!valid_email(email_addr
)) {
1441 reply("NSMSG_BAD_EMAIL_ADDR");
1445 /* .. and that we are allowed to send to it. */
1446 if ((str
= mail_prohibited_address(email_addr
))) {
1447 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1451 /* If we do email verify, make sure we don't spam the address. */
1452 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1454 for (nn
=0; nn
<hil
->used
; nn
++) {
1455 if (hil
->list
[nn
]->cookie
) {
1456 reply("NSMSG_EMAIL_UNACTIVATED");
1460 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1461 reply("NSMSG_EMAIL_OVERUSED");
1474 /* Webregister hack - send URL instead of IRC cookie
1477 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1481 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1483 /* Add any masks they should get. */
1484 if (nickserv_conf
.default_hostmask
) {
1485 string_list_append(hi
->masks
, strdup("*@*"));
1487 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1488 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1489 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1492 /* If they're the first to register, give them level 1000. */
1493 if (dict_size(nickserv_handle_dict
) == 1) {
1494 hi
->opserv_level
= 1000;
1495 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1498 /* Set their email address. */
1501 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1503 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email_addr
)) != LDAP_SUCCESS
) {
1504 /* Falied to update email in ldap, but still
1505 * updated it here.. what should we do? */
1506 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1508 nickserv_set_email_addr(hi
, email_addr
);
1512 nickserv_set_email_addr(hi
, email_addr
);
1515 nickserv_set_email_addr(hi
, email_addr
);
1519 /* If they need to do email verification, tell them. */
1521 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1523 /* Set registering flag.. */
1524 user
->modes
|= FLAGS_REGISTERING
;
1526 if (nickserv_conf
.sync_log
) {
1527 cryptpass(password
, syncpass
);
1529 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1530 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1533 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1536 /* this wont work if email is required .. */
1537 process_adduser_pending(user
);
1542 static NICKSERV_FUNC(cmd_oregister
)
1544 struct userNode
*settee
= NULL
;
1545 struct handle_info
*hi
;
1546 char* account
= NULL
;
1552 NICKSERV_MIN_PARMS(3);
1556 if(nickserv_conf
.force_handles_lowercase
)
1557 irc_strtolower(account
);
1558 if (!is_valid_handle(argv
[1])) {
1559 reply("NSMSG_BAD_HANDLE", argv
[1]);
1562 if (nickserv_conf
.email_required
) {
1563 NICKSERV_MIN_PARMS(3);
1565 if (argc
> 4) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1566 if (strchr(argv
[4], '@'))
1576 if (argc
> 3) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1577 if (strchr(argv
[3], '@'))
1586 /* If they passed a nick, look for that user.. */
1587 if (nick
&& !(settee
= GetUserH(nick
))) {
1588 reply("MSG_NICK_UNKNOWN", argv
[4]);
1591 /* If the setee is already authed, we cant add a 2nd account for them.. */
1592 if (settee
&& settee
->handle_info
) {
1593 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1596 /* If there is no default mask in the conf, and they didn't pass a mask,
1597 * but we did find a user by nick, generate the mask */
1599 if (nickserv_conf
.default_hostmask
)
1602 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1604 reply("NSMSG_REGISTER_BAD_NICKMASK");
1609 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1610 return 0; /* error reply handled by above */
1614 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1616 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email
)) != LDAP_SUCCESS
) {
1617 /* Falied to update email in ldap, but still
1618 * updated it here.. what should we do? */
1619 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1621 nickserv_set_email_addr(hi
, email
);
1625 nickserv_set_email_addr(hi
, email
);
1628 nickserv_set_email_addr(hi
, email
);
1632 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1633 if (mask_canonicalized
)
1634 string_list_append(hi
->masks
, mask_canonicalized
);
1639 if (nickserv_conf
.sync_log
)
1640 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1645 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1648 struct userNode
*target
;
1649 char *new_mask
= strdup(pretty_mask(mask
));
1650 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1651 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1652 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1657 string_list_append(hi
->ignores
, new_mask
);
1658 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1660 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1661 irc_silence(target
, new_mask
, 1);
1666 static NICKSERV_FUNC(cmd_addignore
)
1668 NICKSERV_MIN_PARMS(2);
1670 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1673 static NICKSERV_FUNC(cmd_oaddignore
)
1675 struct handle_info
*hi
;
1677 NICKSERV_MIN_PARMS(3);
1678 if (!(hi
= get_victim_oper(user
, argv
[1])))
1681 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1685 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1688 struct userNode
*target
;
1689 char *pmask
= strdup(pretty_mask(del_mask
));
1690 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1691 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1692 char *old_mask
= hi
->ignores
->list
[i
];
1693 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1694 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1695 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1696 irc_silence(target
, old_mask
, 0);
1703 reply("NSMSG_DELMASK_NOT_FOUND");
1707 static NICKSERV_FUNC(cmd_delignore
)
1709 NICKSERV_MIN_PARMS(2);
1710 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1713 static NICKSERV_FUNC(cmd_odelignore
)
1715 struct handle_info
*hi
;
1716 NICKSERV_MIN_PARMS(3);
1717 if (!(hi
= get_victim_oper(user
, argv
[1])))
1719 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1722 static NICKSERV_FUNC(cmd_handleinfo
)
1725 unsigned int i
, pos
=0, herelen
;
1726 struct userNode
*target
, *next_un
;
1727 struct handle_info
*hi
;
1728 const char *nsmsg_none
;
1731 if (!(hi
= user
->handle_info
)) {
1732 reply("NSMSG_MUST_AUTH");
1735 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1739 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1740 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1742 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1745 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1746 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1748 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1751 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1752 if (HANDLE_FLAGGED(hi
, FROZEN
))
1753 reply("NSMSG_HANDLEINFO_VACATION");
1755 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1756 struct do_not_register
*dnr
;
1757 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1758 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1759 if ((user
->handle_info
->opserv_level
< 900) && !oper_outranks(user
, hi
))
1761 } else if (hi
!= user
->handle_info
) {
1762 reply("NSMSG_HANDLEINFO_END");
1767 reply("NSMSG_HANDLEINFO_KARMA", hi
->karma
);
1769 if (nickserv_conf
.email_enabled
)
1770 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1774 switch (hi
->cookie
->type
) {
1775 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1776 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1777 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1778 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1779 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1782 if (IsOper(user
) && (hi
->cookie
->type
== EMAIL_CHANGE
))
1783 reply("NSMSG_HANDLEINFO_COOKIE_EMAIL_DATA", hi
->cookie
->data
);
1787 unsigned long flen
= 1;
1788 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1790 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1791 if (hi
->flags
& 1 << i
)
1792 flags
[flen
++] = handle_flags
[i
];
1794 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1796 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1799 if (hi
->opserv_level
> 0) {
1800 reply("NSMSG_HANDLEINFO_OPSERV_LEVEL", hi
->opserv_level
);
1803 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1804 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1805 || (hi
->opserv_level
> 0)) {
1806 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1809 if (IsHelping(user
) || IsOper(user
))
1814 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1815 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1820 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1822 if (hi
->last_quit_host
[0])
1823 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1825 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1827 if (nickserv_conf
.disable_nicks
) {
1828 /* nicks disabled; don't show anything about registered nicks */
1829 } else if (hi
->nicks
) {
1830 struct nick_info
*ni
, *next_ni
;
1831 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1832 herelen
= strlen(ni
->nick
);
1833 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1835 goto print_nicks_buff
;
1839 memcpy(buff
+pos
, ni
->nick
, herelen
);
1840 pos
+= herelen
; buff
[pos
++] = ' ';
1844 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1849 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1852 if (hi
->masks
->used
) {
1853 for (i
=0; i
< hi
->masks
->used
; i
++) {
1854 herelen
= strlen(hi
->masks
->list
[i
]);
1855 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1857 goto print_mask_buff
;
1859 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1860 pos
+= herelen
; buff
[pos
++] = ' ';
1861 if (i
+1 == hi
->masks
->used
) {
1864 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1869 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1872 if (hi
->sslfps
->used
) {
1873 for (i
=0; i
< hi
->sslfps
->used
; i
++) {
1874 herelen
= strlen(hi
->sslfps
->list
[i
]);
1875 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1877 goto print_sslfp_buff
;
1879 memcpy(buff
+pos
, hi
->sslfps
->list
[i
], herelen
);
1880 pos
+= herelen
; buff
[pos
++] = ' ';
1881 if (i
+1 == hi
->sslfps
->used
) {
1884 reply("NSMSG_HANDLEINFO_SSLFPS", buff
);
1889 reply("NSMSG_HANDLEINFO_SSLFPS", nsmsg_none
);
1892 if (hi
->ignores
->used
) {
1893 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1894 herelen
= strlen(hi
->ignores
->list
[i
]);
1895 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1897 goto print_ignore_buff
;
1899 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1900 pos
+= herelen
; buff
[pos
++] = ' ';
1901 if (i
+1 == hi
->ignores
->used
) {
1904 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1909 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1913 struct userData
*chan
, *next
;
1916 for (chan
= hi
->channels
; chan
; chan
= next
) {
1917 next
= chan
->u_next
;
1918 name
= chan
->channel
->channel
->name
;
1919 herelen
= strlen(name
);
1920 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1922 goto print_chans_buff
;
1924 if (IsUserSuspended(chan
))
1926 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(chan
->access
), name
);
1930 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1935 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1938 for (target
= hi
->users
; target
; target
= next_un
) {
1939 herelen
= strlen(target
->nick
);
1940 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1942 goto print_cnick_buff
;
1944 next_un
= target
->next_authed
;
1946 memcpy(buff
+pos
, target
->nick
, herelen
);
1947 pos
+= herelen
; buff
[pos
++] = ' ';
1951 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1956 reply("NSMSG_HANDLEINFO_END");
1957 return 1 | ((hi
!= user
->handle_info
) ? CMD_LOG_STAFF
: 0);
1960 static NICKSERV_FUNC(cmd_userinfo
)
1962 struct userNode
*target
;
1964 NICKSERV_MIN_PARMS(2);
1965 if (!(target
= GetUserH(argv
[1]))) {
1966 reply("MSG_NICK_UNKNOWN", argv
[1]);
1969 if (target
->handle_info
)
1970 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1972 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1976 static NICKSERV_FUNC(cmd_nickinfo
)
1978 struct nick_info
*ni
;
1981 NICKSERV_MIN_PARMS(2);
1982 if (!(ni
= get_nick_info(argv
[1]))) {
1983 reply("MSG_NICK_UNKNOWN", argv
[1]);
1987 reply("NSMSG_NICKINFO_ON", ni
->nick
);
1989 reply("NSMSG_NICKINFO_REGGED", ctime(&ni
->registered
));
1991 if (!GetUserH(ni
->nick
)) {
1992 intervalString(buff
, now
- ni
->lastseen
, user
->handle_info
);
1993 reply("NSMSG_NICKINFO_LASTSEEN", buff
);
1995 reply("NSMSG_NICKINFO_LASTSEEN_NOW");
1998 reply("NSMSG_NICKINFO_OWNER", ni
->owner
->handle
);
2000 reply("NSMSG_NICKINFO_END");
2005 static NICKSERV_FUNC(cmd_rename_handle
)
2007 struct handle_info
*hi
;
2008 struct userNode
*uNode
;
2012 NICKSERV_MIN_PARMS(3);
2013 if(nickserv_conf
.force_handles_lowercase
)
2014 irc_strtolower(argv
[2]);
2015 if (!(hi
= get_victim_oper(user
, argv
[1])))
2017 if (!is_valid_handle(argv
[2])) {
2018 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
2021 if (get_handle_info(argv
[2])) {
2022 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
2025 if(strlen(argv
[2]) > 30)
2027 reply("NMSG_HANDLE_TOLONG", argv
[2], 30);
2031 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2033 if( (rc
= ldap_rename_account(hi
->handle
, argv
[2])) != LDAP_SUCCESS
) {
2034 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2040 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
2041 hi
->handle
= strdup(argv
[2]);
2042 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
2043 for (nn
=0; nn
<rf_list_used
; nn
++)
2044 rf_list
[nn
](hi
, old_handle
, rf_list_extra
[nn
]);
2046 if (nickserv_conf
.sync_log
) {
2047 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2048 irc_rename(uNode
, hi
->handle
);
2050 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
2053 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
2054 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
2055 user
->handle_info
->handle
, old_handle
, hi
->handle
);
2061 static failpw_func_t
*failpw_func_list
;
2062 static void **failpw_func_list_extra
;
2063 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
2066 reg_failpw_func(failpw_func_t func
, void *extra
)
2068 if (failpw_func_used
== failpw_func_size
) {
2069 if (failpw_func_size
) {
2070 failpw_func_size
<<= 1;
2071 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
2072 failpw_func_list_extra
= realloc(failpw_func_list_extra
, failpw_func_size
*sizeof(void*));
2074 failpw_func_size
= 8;
2075 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
2076 failpw_func_list_extra
= malloc(failpw_func_size
*sizeof(void*));
2079 failpw_func_list
[failpw_func_used
] = func
;
2080 failpw_func_list_extra
[failpw_func_used
++] = extra
;
2084 * Return hi for the first handle that has a matching SSL fingerprint.
2086 struct handle_info
*find_handleinfo_by_sslfp(char *sslfp
)
2089 struct handle_info
*hi
;
2090 unsigned int ii
= 0;;
2092 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2094 for (ii
=0; ii
<hi
->sslfps
->used
; ii
++) {
2095 if (!irccasecmp(sslfp
, hi
->sslfps
->list
[ii
])) {
2105 * Return hi if the handle/pass pair matches, NULL if it doesnt.
2107 * called by nefariouses enhanced AC login-on-connect code
2110 struct handle_info
*loc_auth(char *sslfp
, char *handle
, char *password
, char *userhost
)
2112 int wildmask
= 0, auth
= 0;
2113 int used
, maxlogins
;
2115 struct handle_info
*hi
= NULL
;
2116 struct userNode
*other
;
2118 int ldap_result
= LDAP_SUCCESS
;
2123 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
2124 if (!hi
&& (sslfp
!= NULL
)) {
2125 hi
= find_handleinfo_by_sslfp(sslfp
);
2126 if (!handle
&& (hi
!= NULL
))
2127 handle
= hi
->handle
;
2130 /* Ensure handle is valid if not found in internal DB */
2131 if (!hi
&& (!handle
|| !is_valid_handle(handle
)))
2135 if (nickserv_conf
.ldap_enable
&& (password
!= NULL
)) {
2136 ldap_result
= ldap_check_auth(handle
, password
);
2137 if (!hi
&& (ldap_result
!= LDAP_SUCCESS
))
2139 if (ldap_result
== LDAP_SUCCESS
) {
2140 /* Mark auth as successful */
2144 if (!hi
&& (ldap_result
== LDAP_SUCCESS
) && nickserv_conf
.ldap_autocreate
) {
2145 /* user not found, but authed to ldap successfully..
2146 * create the account.
2151 /* Add a *@* mask */
2152 /* TODO if userhost is not null, build mask based on that. */
2153 if(nickserv_conf
.default_hostmask
)
2156 return NULL
; /* They dont have a *@* mask so they can't loc */
2158 if(!(hi
= nickserv_register(NULL
, NULL
, handle
, password
, 0))) {
2159 return 0; /* couldn't add the user for some reason */
2162 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2164 if(nickserv_conf
.email_required
) {
2169 nickserv_set_email_addr(hi
, email
);
2173 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2174 string_list_append(hi
->masks
, mask_canonicalized
);
2176 if(nickserv_conf
.sync_log
)
2177 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, "@", handle
);
2182 /* hi should now be a valid handle, if not return NULL */
2187 if (password
&& *password
&& !nickserv_conf
.ldap_enable
) {
2189 if (password
&& *password
) {
2191 if (checkpass(password
, hi
->passwd
))
2195 if (!auth
&& sslfp
&& *sslfp
&& hi
->sslfps
->used
) {
2196 /* If any SSL fingerprint matches, allow it. */
2197 for (ii
=0; ii
<hi
->sslfps
->used
; ii
++) {
2198 if (!irccasecmp(sslfp
, hi
->sslfps
->list
[ii
])) {
2205 /* Auth should have succeeded by this point */
2209 /* We don't know the users hostname, or anything because they
2210 * havn't registered yet. So we can only allow LOC if your
2211 * account has *@* as a hostmask.
2213 * UPDATE: New nefarious LOC supports u@h
2218 char *realhost
= NULL
;
2225 buf
= strdup(userhost
);
2228 for (c
= buf
; *c
; c
++) {
2229 if ((realhost
== NULL
) && (*c
== '@')) {
2236 } else if (bracket
&& (ip
== NULL
) && (*c
== ']')) {
2239 } else if (!bracket
&& (ip
== NULL
) && (*c
== ':')) {
2246 log_module(NS_LOG
, LOG_DEBUG
, "LOC: ident=%s host=%s ip=%s", ident
, realhost
, ip
);
2248 if(!ip
|| !realhost
|| !ident
) {
2250 return NULL
; /* Invalid AC request, just quit */
2252 uh
= malloc(strlen(userhost
));
2253 ui
= malloc(strlen(userhost
));
2254 sprintf(uh
, "%s@%s", ident
, realhost
);
2255 sprintf(ui
, "%s@%s", ident
, ip
);
2256 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2258 if(match_ircglob(uh
, hi
->masks
->list
[ii
])
2259 || match_ircglob(ui
, hi
->masks
->list
[ii
]))
2271 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2273 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
2283 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2287 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2288 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2289 if (++used
>= maxlogins
) {
2293 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2297 void nickserv_do_autoauth(struct userNode
*user
)
2299 struct handle_info
*hi
;
2300 struct userNode
*other
;
2301 int used
, maxlogins
;
2303 /* Already authed, nothing to do */
2304 if (user
->handle_info
)
2307 /* No client certificate fingerprint, cant auto auth */
2311 hi
= find_handleinfo_by_sslfp(user
->sslfp
);
2315 /* User doesn't match host masks */
2316 if (!valid_user_for(user
, hi
)) {
2317 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
2318 send_message_type(4, user
, nickserv
,
2319 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
2322 send_message_type(4, user
, nickserv
,
2323 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
2328 /* Account suspended? */
2329 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2330 send_message_type(4, user
, nickserv
,
2331 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2335 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2336 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2337 if (++used
>= maxlogins
) {
2338 send_message_type(4, user
, nickserv
,
2339 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2345 set_user_handle_info(user
, hi
, 1);
2346 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2347 send_message_type(4, user
, nickserv
,
2348 handle_find_message(hi
, "NSMSG_PLEASE_SET_EMAIL"));
2350 /* If a channel was waiting for this user to auth,
2351 * finish adding them */
2352 process_adduser_pending(user
);
2354 send_message_type(4, user
, nickserv
,
2355 handle_find_message(hi
, "NSMSG_AUTH_SUCCESS"));
2357 /* Set +x if autohide is on */
2358 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2359 irc_umode(user
, "+x");
2362 static NICKSERV_FUNC(cmd_auth
)
2364 int pw_arg
, used
, maxlogins
;
2366 struct handle_info
*hi
;
2369 struct userNode
*other
;
2371 int ldap_result
= LDAP_OTHER
;
2375 if (user
->handle_info
) {
2376 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2379 if (IsStamped(user
)) {
2380 /* Unauthenticated users might still have been stamped
2381 previously and could therefore have a hidden host;
2382 do not allow them to authenticate. */
2383 reply("NSMSG_STAMPED_AUTH");
2390 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
2391 } else if (argc
== 2) {
2394 if (nickserv_conf
.disable_nicks
) {
2395 hi
= get_handle_info(user
->nick
);
2397 /* try to look up their handle from their nick */
2398 /* TODO: handle ldap auth on nickserv style networks, too */
2399 struct nick_info
*ni
;
2400 ni
= get_nick_info(user
->nick
);
2402 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
2408 handle
= hi
->handle
;
2410 handle
= user
->nick
;
2413 reply("MSG_MISSING_PARAMS", argv
[0]);
2414 svccmd_send_help_brief(user
, nickserv
, cmd
);
2419 if(strchr(handle
, '<') || strchr(handle
, '>')) {
2420 reply("NSMSG_NO_ANGLEBRACKETS");
2423 if (!is_valid_handle(handle
)) {
2424 reply("NSMSG_BAD_HANDLE", handle
);
2428 if(nickserv_conf
.ldap_enable
) {
2429 ldap_result
= ldap_check_auth(handle
, passwd
);
2430 /* Get the users email address and update it */
2431 if(ldap_result
== LDAP_SUCCESS
) {
2433 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2435 if(nickserv_conf
.email_required
) {
2436 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc
));
2441 else if(ldap_result
!= LDAP_INVALID_CREDENTIALS
) {
2442 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2450 if(nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2451 /* user not found, but authed to ldap successfully..
2452 * create the account.
2455 if(!(hi
= nickserv_register(user
, user
, handle
, passwd
, 0))) {
2456 reply("NSMSG_UNABLE_TO_ADD");
2457 return 0; /* couldn't add the user for some reason */
2459 /* Add a *@* mask */
2460 if(nickserv_conf
.default_hostmask
)
2463 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2466 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2467 string_list_append(hi
->masks
, mask_canonicalized
);
2470 nickserv_set_email_addr(hi
, email
);
2473 if(nickserv_conf
.sync_log
)
2474 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
);
2478 reply("NSMSG_HANDLE_NOT_FOUND");
2484 /* Responses from here on look up the language used by the handle they asked about. */
2485 if (!valid_user_for(user
, hi
)) {
2486 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
2487 send_message_type(4, user
, cmd
->parent
->bot
,
2488 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
2491 send_message_type(4, user
, cmd
->parent
->bot
,
2492 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
2494 argv
[pw_arg
] = "BADMASK";
2498 if (valid_user_sslfp(user
, hi
))
2502 if(( ( nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_INVALID_CREDENTIALS
) ||
2503 ( (!nickserv_conf
.ldap_enable
) && (!checkpass(passwd
, hi
->passwd
)) ) ) && !sslfpauth
) {
2505 if (!checkpass(passwd
, hi
->passwd
) && !sslfpauth
) {
2508 send_message_type(4, user
, cmd
->parent
->bot
,
2509 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
2510 argv
[pw_arg
] = "BADPASS";
2511 for (n
=0; n
<failpw_func_used
; n
++)
2512 failpw_func_list
[n
](user
, hi
, failpw_func_list_extra
[n
]);
2513 if (nickserv_conf
.autogag_enabled
) {
2514 if (!user
->auth_policer
.params
) {
2515 user
->auth_policer
.last_req
= now
;
2516 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
2518 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
2520 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
2521 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
2522 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2524 argv
[pw_arg
] = "GAGGED";
2529 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2530 send_message_type(4, user
, cmd
->parent
->bot
,
2531 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2532 argv
[pw_arg
] = "SUSPENDED";
2535 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2536 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2537 if (++used
>= maxlogins
) {
2538 send_message_type(4, user
, cmd
->parent
->bot
,
2539 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2541 argv
[pw_arg
] = "MAXLOGINS";
2546 set_user_handle_info(user
, hi
, 1);
2547 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2548 reply("NSMSG_PLEASE_SET_EMAIL");
2549 if (!sslfpauth
&& !is_secure_password(hi
->handle
, passwd
, NULL
))
2550 reply("NSMSG_WEAK_PASSWORD");
2551 if (!sslfpauth
&& (hi
->passwd
[0] != '$'))
2552 cryptpass(passwd
, hi
->passwd
);
2554 /* If a channel was waiting for this user to auth,
2555 * finish adding them */
2556 process_adduser_pending(user
);
2558 reply("NSMSG_AUTH_SUCCESS");
2561 /* Set +x if autohide is on */
2562 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2563 irc_umode(user
, "+x");
2565 if (!hi
->masks
->used
) {
2567 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2568 if (irc_in_addr_is_valid(user
->ip
) && irc_pton(&ip
, NULL
, user
->hostname
))
2569 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2572 /* Wipe out the pass for the logs */
2573 argv
[pw_arg
] = "****";
2577 static allowauth_func_t
*allowauth_func_list
;
2578 static void **allowauth_func_list_extra
;
2579 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2582 reg_allowauth_func(allowauth_func_t func
, void *extra
)
2584 if (allowauth_func_used
== allowauth_func_size
) {
2585 if (allowauth_func_size
) {
2586 allowauth_func_size
<<= 1;
2587 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2588 allowauth_func_list_extra
= realloc(allowauth_func_list_extra
, allowauth_func_size
*sizeof(void*));
2590 allowauth_func_size
= 8;
2591 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2592 allowauth_func_list_extra
= malloc(allowauth_func_size
*sizeof(void*));
2595 allowauth_func_list
[allowauth_func_used
] = func
;
2596 allowauth_func_list_extra
[allowauth_func_used
++] = extra
;
2599 static NICKSERV_FUNC(cmd_allowauth
)
2601 struct userNode
*target
;
2602 struct handle_info
*hi
;
2605 NICKSERV_MIN_PARMS(2);
2606 if (!(target
= GetUserH(argv
[1]))) {
2607 reply("MSG_NICK_UNKNOWN", argv
[1]);
2610 if (target
->handle_info
) {
2611 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2614 if (IsStamped(target
)) {
2615 /* Unauthenticated users might still have been stamped
2616 previously and could therefore have a hidden host;
2617 do not allow them to authenticate to an account. */
2618 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2623 else if (!(hi
= get_handle_info(argv
[2]))) {
2624 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2628 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2629 reply("MSG_USER_OUTRANKED", hi
->handle
);
2632 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2633 || (hi
->opserv_level
> 0))
2634 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2635 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2638 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2639 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2640 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2641 if (nickserv_conf
.email_enabled
)
2642 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2644 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2645 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2647 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2649 for (n
=0; n
<allowauth_func_used
; n
++)
2650 allowauth_func_list
[n
](user
, target
, hi
, allowauth_func_list_extra
[n
]);
2654 static NICKSERV_FUNC(cmd_authcookie
)
2656 struct handle_info
*hi
;
2658 NICKSERV_MIN_PARMS(2);
2659 if (user
->handle_info
) {
2660 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2663 if (IsStamped(user
)) {
2664 /* Unauthenticated users might still have been stamped
2665 previously and could therefore have a hidden host;
2666 do not allow them to authenticate to an account. */
2667 reply("NSMSG_STAMPED_AUTHCOOKIE");
2670 if (!(hi
= get_handle_info(argv
[1]))) {
2671 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2674 if (!hi
->email_addr
) {
2675 reply("MSG_SET_EMAIL_ADDR");
2678 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2682 static NICKSERV_FUNC(cmd_delcookie
)
2684 struct handle_info
*hi
;
2686 hi
= user
->handle_info
;
2688 reply("NSMSG_NO_COOKIE");
2691 switch (hi
->cookie
->type
) {
2694 reply("NSMSG_MUST_TIME_OUT");
2697 nickserv_eat_cookie(hi
->cookie
);
2698 reply("NSMSG_ATE_COOKIE");
2704 static NICKSERV_FUNC(cmd_odelcookie
)
2706 struct handle_info
*hi
;
2708 NICKSERV_MIN_PARMS(2);
2710 if (!(hi
= get_victim_oper(user
, argv
[1])))
2714 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2718 switch (hi
->cookie
->type
) {
2720 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2722 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2724 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2725 /* Falied to update password in ldap, but still
2726 * updated it here.. what should we do? */
2727 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2732 if (nickserv_conf
.sync_log
)
2733 SyncLog("ACCOUNTACC %s", hi
->handle
);
2735 case PASSWORD_CHANGE
:
2742 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2743 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2747 nickserv_eat_cookie(hi
->cookie
);
2748 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2753 static NICKSERV_FUNC(cmd_resetpass
)
2755 struct handle_info
*hi
;
2756 char crypted
[MD5_CRYPT_LENGTH
];
2759 NICKSERV_MIN_PARMS(3);
2760 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2764 if (user
->handle_info
) {
2765 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2768 if (IsStamped(user
)) {
2769 /* Unauthenticated users might still have been stamped
2770 previously and could therefore have a hidden host;
2771 do not allow them to activate an account. */
2772 reply("NSMSG_STAMPED_RESETPASS");
2775 if (!(hi
= get_handle_info(argv
[1]))) {
2776 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2779 if (!hi
->email_addr
) {
2780 reply("MSG_SET_EMAIL_ADDR");
2783 cryptpass(argv
[2], crypted
);
2785 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2789 static NICKSERV_FUNC(cmd_cookie
)
2791 struct handle_info
*hi
;
2794 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2797 NICKSERV_MIN_PARMS(3);
2798 if (!(hi
= get_handle_info(argv
[1]))) {
2799 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2805 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2806 reply("NSMSG_HANDLE_SUSPENDED");
2811 reply("NSMSG_NO_COOKIE");
2815 /* Check validity of operation before comparing cookie to
2816 * prohibit guessing by authed users. */
2817 if (user
->handle_info
2818 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2819 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2820 reply("NSMSG_CANNOT_COOKIE");
2824 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2825 reply("NSMSG_BAD_COOKIE");
2829 switch (hi
->cookie
->type
) {
2832 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2834 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2835 /* Falied to update email in ldap, but still
2836 * updated it here.. what should we do? */
2837 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2842 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2843 set_user_handle_info(user
, hi
, 1);
2844 reply("NSMSG_HANDLE_ACTIVATED");
2845 if (nickserv_conf
.sync_log
)
2846 SyncLog("ACCOUNTACC %s", hi
->handle
);
2848 case PASSWORD_CHANGE
:
2850 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2852 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2853 /* Falied to update email in ldap, but still
2854 * updated it here.. what should we do? */
2855 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2860 set_user_handle_info(user
, hi
, 1);
2861 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2862 reply("NSMSG_PASSWORD_CHANGED");
2863 if (nickserv_conf
.sync_log
)
2864 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2868 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2870 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2871 /* Falied to update email in ldap, but still
2872 * updated it here.. what should we do? */
2873 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2878 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2880 * This should only happen if an OREGISTER was sent. Require
2881 * email must be enabled! - SiRVulcaN
2883 if (nickserv_conf
.sync_log
)
2884 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2887 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2888 reply("NSMSG_EMAIL_CHANGED");
2889 if (nickserv_conf
.sync_log
)
2890 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2893 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2894 set_user_handle_info(user
, hi
, 1);
2895 nickserv_addmask(user
, hi
, mask
);
2896 reply("NSMSG_AUTH_SUCCESS");
2901 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2902 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2906 nickserv_eat_cookie(hi
->cookie
);
2908 process_adduser_pending(user
);
2913 static NICKSERV_FUNC(cmd_oregnick
) {
2915 struct handle_info
*target
;
2916 struct nick_info
*ni
;
2918 NICKSERV_MIN_PARMS(3);
2919 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2922 if (!is_registerable_nick(nick
)) {
2923 reply("NSMSG_BAD_NICK", nick
);
2926 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2928 reply("NSMSG_NICK_EXISTS", nick
);
2931 register_nick(nick
, target
);
2932 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2936 static NICKSERV_FUNC(cmd_regnick
) {
2938 struct nick_info
*ni
;
2940 if (!is_registerable_nick(user
->nick
)) {
2941 reply("NSMSG_BAD_NICK", user
->nick
);
2944 /* count their nicks, see if it's too many */
2945 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2946 if (n
>= nickserv_conf
.nicks_per_handle
) {
2947 reply("NSMSG_TOO_MANY_NICKS");
2950 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2952 reply("NSMSG_NICK_EXISTS", user
->nick
);
2955 register_nick(user
->nick
, user
->handle_info
);
2956 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2960 static NICKSERV_FUNC(cmd_pass
)
2962 struct handle_info
*hi
;
2963 char *old_pass
, *new_pass
;
2964 char crypted
[MD5_CRYPT_LENGTH
+1];
2969 NICKSERV_MIN_PARMS(3);
2970 hi
= user
->handle_info
;
2974 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2977 if(nickserv_conf
.ldap_enable
) {
2978 ldap_result
= ldap_check_auth(hi
->handle
, old_pass
);
2979 if(ldap_result
!= LDAP_SUCCESS
) {
2980 if(ldap_result
== LDAP_INVALID_CREDENTIALS
)
2981 reply("NSMSG_PASSWORD_INVALID");
2983 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2988 if (!checkpass(old_pass
, hi
->passwd
)) {
2989 argv
[1] = "BADPASS";
2990 reply("NSMSG_PASSWORD_INVALID");
2993 cryptpass(new_pass
, crypted
);
2995 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2997 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
2998 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3003 //cryptpass(new_pass, hi->passwd);
3004 strcpy(hi
->passwd
, crypted
);
3005 if (nickserv_conf
.sync_log
)
3006 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
3008 reply("NSMSG_PASS_SUCCESS");
3013 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
3016 char *new_mask
= canonicalize_hostmask(strdup(mask
));
3017 for (i
=0; i
<hi
->masks
->used
; i
++) {
3018 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
3019 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
3024 string_list_append(hi
->masks
, new_mask
);
3025 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
3029 static NICKSERV_FUNC(cmd_addmask
)
3032 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
3033 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
3037 if (!is_gline(argv
[1])) {
3038 reply("NSMSG_MASK_INVALID", argv
[1]);
3041 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
3045 static NICKSERV_FUNC(cmd_oaddmask
)
3047 struct handle_info
*hi
;
3049 NICKSERV_MIN_PARMS(3);
3050 if (!(hi
= get_victim_oper(user
, argv
[1])))
3052 return nickserv_addmask(user
, hi
, argv
[2]);
3056 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
, int force
)
3059 for (i
=0; i
<hi
->masks
->used
; i
++) {
3060 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
3061 char *old_mask
= hi
->masks
->list
[i
];
3062 if (hi
->masks
->used
== 1 && !force
) {
3063 reply("NSMSG_DELMASK_NOTLAST");
3066 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
3067 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
3072 reply("NSMSG_DELMASK_NOT_FOUND");
3076 static NICKSERV_FUNC(cmd_delmask
)
3078 NICKSERV_MIN_PARMS(2);
3079 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1], 0);
3082 static NICKSERV_FUNC(cmd_odelmask
)
3084 struct handle_info
*hi
;
3085 NICKSERV_MIN_PARMS(3);
3086 if (!(hi
= get_victim_oper(user
, argv
[1])))
3088 return nickserv_delmask(cmd
, user
, hi
, argv
[2], 1);
3092 nickserv_addsslfp(struct userNode
*user
, struct handle_info
*hi
, const char *sslfp
)
3095 char *new_sslfp
= strdup(sslfp
);
3096 for (i
=0; i
<hi
->sslfps
->used
; i
++) {
3097 if (!irccasecmp(new_sslfp
, hi
->sslfps
->list
[i
])) {
3098 send_message(user
, nickserv
, "NSMSG_ADDSSLFP_ALREADY", new_sslfp
);
3103 string_list_append(hi
->sslfps
, new_sslfp
);
3104 send_message(user
, nickserv
, "NSMSG_ADDSSLFP_SUCCESS", new_sslfp
);
3108 static NICKSERV_FUNC(cmd_addsslfp
)
3110 NICKSERV_MIN_PARMS((user
->sslfp
? 1 : 2));
3111 if ((argc
< 2) && (user
->sslfp
)) {
3112 int res
= nickserv_addsslfp(user
, user
->handle_info
, user
->sslfp
);
3115 return nickserv_addsslfp(user
, user
->handle_info
, argv
[1]);
3119 static NICKSERV_FUNC(cmd_oaddsslfp
)
3121 struct handle_info
*hi
;
3123 NICKSERV_MIN_PARMS(3);
3124 if (!(hi
= get_victim_oper(user
, argv
[1])))
3126 return nickserv_addsslfp(user
, hi
, argv
[2]);
3130 nickserv_delsslfp(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_sslfp
)
3133 for (i
=0; i
<hi
->sslfps
->used
; i
++) {
3134 if (!irccasecmp(del_sslfp
, hi
->sslfps
->list
[i
])) {
3135 char *old_sslfp
= hi
->sslfps
->list
[i
];
3136 hi
->sslfps
->list
[i
] = hi
->sslfps
->list
[--hi
->sslfps
->used
];
3137 reply("NSMSG_DELSSLFP_SUCCESS", old_sslfp
);
3142 reply("NSMSG_DELSSLFP_NOT_FOUND");
3146 static NICKSERV_FUNC(cmd_delsslfp
)
3148 NICKSERV_MIN_PARMS((user
->sslfp
? 1 : 2));
3149 if ((argc
< 2) && (user
->sslfp
)) {
3150 return nickserv_delsslfp(cmd
, user
, user
->handle_info
, user
->sslfp
);
3152 return nickserv_delsslfp(cmd
, user
, user
->handle_info
, argv
[1]);
3156 static NICKSERV_FUNC(cmd_odelsslfp
)
3158 struct handle_info
*hi
;
3159 NICKSERV_MIN_PARMS(3);
3160 if (!(hi
= get_victim_oper(user
, argv
[1])))
3162 return nickserv_delsslfp(cmd
, user
, hi
, argv
[2]);
3166 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
3167 unsigned int nn
, add
= 1, pos
;
3168 unsigned long added
, removed
, flag
;
3170 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
3172 case '+': add
= 1; break;
3173 case '-': add
= 0; break;
3175 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
3176 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
3179 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
3180 /* cheesy avoidance of looking up the flag name.. */
3181 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
3184 flag
= 1 << (pos
- 1);
3186 added
|= flag
, removed
&= ~flag
;
3188 removed
|= flag
, added
&= ~flag
;
3193 *premoved
= removed
;
3198 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
3200 unsigned long before
, after
, added
, removed
;
3201 struct userNode
*uNode
;
3203 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
3204 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
3206 hi
->flags
= (hi
->flags
| added
) & ~removed
;
3207 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
3209 /* Strip helping flag if they're only a support helper and not
3210 * currently in #support. */
3211 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
3212 struct channelList
*schannels
;
3214 schannels
= chanserv_support_channels();
3215 for (ii
= 0; ii
< schannels
->used
; ++ii
)
3216 if (find_handle_in_channel(schannels
->list
[ii
], hi
, NULL
))
3218 if (ii
== schannels
->used
)
3219 HANDLE_CLEAR_FLAG(hi
, HELPING
);
3222 if (after
&& !before
) {
3223 /* Add user to current helper list. */
3224 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
3225 userList_append(&curr_helpers
, uNode
);
3226 } else if (!after
&& before
) {
3227 /* Remove user from current helper list. */
3228 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
3229 userList_remove(&curr_helpers
, uNode
);
3236 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
3240 char *set_display
[] = {
3241 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
3242 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
3243 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
3246 reply("NSMSG_SETTING_LIST");
3247 reply("NSMSG_SETTING_LIST_HEADER");
3249 /* Do this so options are presented in a consistent order. */
3250 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
3251 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
3252 opt(cmd
, user
, hi
, override
, 0, 0, NULL
);
3253 reply("NSMSG_SETTING_LIST_END");
3256 static NICKSERV_FUNC(cmd_set
)
3258 struct handle_info
*hi
;
3261 hi
= user
->handle_info
;
3263 set_list(cmd
, user
, hi
, 0);
3266 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
3267 reply("NSMSG_INVALID_OPTION", argv
[1]);
3270 return opt(cmd
, user
, hi
, 0, 0, argc
-1, argv
+1);
3273 static NICKSERV_FUNC(cmd_oset
)
3275 struct handle_info
*hi
;
3278 NICKSERV_MIN_PARMS(2);
3280 if (!(hi
= get_victim_oper(user
, argv
[1])))
3284 set_list(cmd
, user
, hi
, 0);
3288 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
3289 reply("NSMSG_INVALID_OPTION", argv
[2]);
3293 return opt(cmd
, user
, hi
, 1, 0, argc
-2, argv
+2);
3296 static OPTION_FUNC(opt_info
)
3300 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
3302 hi
->infoline
= NULL
;
3304 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
3308 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
3310 reply("NSMSG_SET_INFO", info
);
3314 static OPTION_FUNC(opt_width
)
3317 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
3319 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
3320 hi
->screen_width
= MIN_LINE_SIZE
;
3321 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3322 hi
->screen_width
= MAX_LINE_SIZE
;
3325 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
3329 static OPTION_FUNC(opt_tablewidth
)
3332 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
3334 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
3335 hi
->table_width
= MIN_LINE_SIZE
;
3336 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3337 hi
->table_width
= MAX_LINE_SIZE
;
3340 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
3344 static OPTION_FUNC(opt_color
)
3347 if (enabled_string(argv
[1]))
3348 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
3349 else if (disabled_string(argv
[1]))
3350 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
3353 reply("MSG_INVALID_BINARY", argv
[1]);
3359 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
3363 static OPTION_FUNC(opt_privmsg
)
3366 if (enabled_string(argv
[1]))
3367 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
3368 else if (disabled_string(argv
[1]))
3369 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
3372 reply("MSG_INVALID_BINARY", argv
[1]);
3378 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
3382 static OPTION_FUNC(opt_autohide
)
3385 if (enabled_string(argv
[1]))
3386 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
3387 else if (disabled_string(argv
[1]))
3388 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
3391 reply("MSG_INVALID_BINARY", argv
[1]);
3397 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
3401 static OPTION_FUNC(opt_style
)
3406 if (!irccasecmp(argv
[1], "Clean"))
3407 hi
->userlist_style
= HI_STYLE_CLEAN
;
3408 else if (!irccasecmp(argv
[1], "Advanced"))
3409 hi
->userlist_style
= HI_STYLE_ADVANCED
;
3410 else if (!irccasecmp(argv
[1], "Classic"))
3411 hi
->userlist_style
= HI_STYLE_CLASSIC
;
3412 else /* Default to normal */
3413 hi
->userlist_style
= HI_STYLE_NORMAL
;
3414 } /* TODO: give error if unknow style is chosen */
3416 switch (hi
->userlist_style
) {
3417 case HI_STYLE_ADVANCED
:
3420 case HI_STYLE_CLASSIC
:
3423 case HI_STYLE_CLEAN
:
3426 case HI_STYLE_NORMAL
:
3432 reply("NSMSG_SET_STYLE", style
);
3436 static OPTION_FUNC(opt_announcements
)
3441 if (enabled_string(argv
[1]))
3442 hi
->announcements
= 'y';
3443 else if (disabled_string(argv
[1]))
3444 hi
->announcements
= 'n';
3445 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
3446 hi
->announcements
= '?';
3449 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
3454 switch (hi
->announcements
) {
3455 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
3456 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
3457 case '?': choice
= "default"; break;
3458 default: choice
= "unknown"; break;
3461 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
3465 static OPTION_FUNC(opt_password
)
3467 char crypted
[MD5_CRYPT_LENGTH
+1];
3473 reply("NSMSG_USE_CMD_PASS");
3477 cryptpass(argv
[1], crypted
);
3479 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3481 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
3483 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3488 strcpy(hi
->passwd
, crypted
);
3489 if (nickserv_conf
.sync_log
)
3490 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
3493 reply("NSMSG_SET_PASSWORD", "***");
3497 static OPTION_FUNC(opt_flags
)
3500 unsigned int ii
, flen
;
3504 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3509 nickserv_apply_flags(user
, hi
, argv
[1]);
3511 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
3512 if (hi
->flags
& (1 << ii
))
3513 flags
[flen
++] = handle_flags
[ii
];
3517 reply("NSMSG_SET_FLAGS", flags
);
3519 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
3524 static OPTION_FUNC(opt_email
)
3528 if (!valid_email(argv
[1])) {
3530 reply("NSMSG_BAD_EMAIL_ADDR");
3533 if ((str
= mail_prohibited_address(argv
[1]))) {
3535 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
3538 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1])) {
3540 reply("NSMSG_EMAIL_SAME");
3541 } else if (!override
)
3542 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
3545 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3547 if((rc
= ldap_do_modify(hi
->handle
, NULL
, argv
[1])) != LDAP_SUCCESS
) {
3549 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3554 nickserv_set_email_addr(hi
, argv
[1]);
3556 nickserv_eat_cookie(hi
->cookie
);
3558 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3562 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3567 static OPTION_FUNC(opt_maxlogins
)
3569 unsigned char maxlogins
;
3571 maxlogins
= strtoul(argv
[1], NULL
, 0);
3572 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
3574 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
3577 hi
->maxlogins
= maxlogins
;
3579 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
3581 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
3585 static OPTION_FUNC(opt_advanced
)
3588 if (enabled_string(argv
[1]))
3589 HANDLE_SET_FLAG(hi
, ADVANCED
);
3590 else if (disabled_string(argv
[1]))
3591 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
3594 reply("MSG_INVALID_BINARY", argv
[1]);
3600 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
3604 static OPTION_FUNC(opt_language
)
3606 struct language
*lang
;
3608 lang
= language_find(argv
[1]);
3609 if (irccasecmp(lang
->name
, argv
[1])) {
3611 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
3613 hi
->language
= lang
;
3616 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
3620 static OPTION_FUNC(opt_karma
)
3624 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3629 if (argv
[1][0] == '+' && isdigit(argv
[1][1])) {
3630 hi
->karma
+= strtoul(argv
[1] + 1, NULL
, 10);
3631 } else if (argv
[1][0] == '-' && isdigit(argv
[1][1])) {
3632 hi
->karma
-= strtoul(argv
[1] + 1, NULL
, 10);
3635 send_message(user
, nickserv
, "NSMSG_INVALID_KARMA", argv
[1]);
3640 send_message(user
, nickserv
, "NSMSG_SET_KARMA", hi
->karma
);
3644 /* Called from opserv from cmd_access */
3646 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
3647 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
3649 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
3650 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
3651 && (user
->handle_info
->opserv_level
< 1000))) {
3652 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
3655 if ((user
->handle_info
->opserv_level
< new_level
)
3656 || ((user
->handle_info
->opserv_level
== new_level
)
3657 && (user
->handle_info
->opserv_level
< 1000))) {
3658 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
3661 if (user
->handle_info
== target
) {
3662 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
3666 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_oper_group_dn
) && *(nickserv_conf
.ldap_admin_dn
)) {
3668 if(new_level
> nickserv_conf
.ldap_oper_group_level
)
3669 rc
= ldap_add2group(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3671 rc
= ldap_delfromgroup(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3672 if(rc
!= LDAP_SUCCESS
&& rc
!= LDAP_TYPE_OR_VALUE_EXISTS
&& rc
!= LDAP_NO_SUCH_ATTRIBUTE
) {
3673 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3677 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_field_oslevel
) && *(nickserv_conf
.ldap_admin_dn
)) {
3679 if((rc
= ldap_do_oslevel(target
->handle
, new_level
, target
->opserv_level
)) != LDAP_SUCCESS
) {
3680 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3685 if (target
->opserv_level
== new_level
)
3687 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
3688 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
3689 target
->opserv_level
= new_level
;
3693 static OPTION_FUNC(opt_level
)
3699 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3703 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
3705 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
3709 static OPTION_FUNC(opt_epithet
)
3711 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
3713 struct userNode
*target
, *next_un
;
3717 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3721 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
3725 if ((epithet
[0] == '*') && !epithet
[1])
3728 hi
->epithet
= strdup(epithet
);
3730 for (target
= hi
->users
; target
; target
= next_un
) {
3731 irc_swhois(nickserv
, target
, hi
->epithet
);
3733 next_un
= target
->next_authed
;
3739 reply("NSMSG_SET_EPITHET", hi
->epithet
);
3741 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
3746 static OPTION_FUNC(opt_title
)
3749 const char *none
= NULL
;
3752 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
3755 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3760 if(!strcmp(title
, "*")) {
3762 hi
->fakehost
= NULL
;
3765 if (strchr(title
, '.')) {
3767 reply("NSMSG_TITLE_INVALID");
3770 /* Alphanumeric titles only. */
3771 for(sptr
= title
; *sptr
; sptr
++) {
3772 if(!isalnum(*sptr
) && *sptr
!= '-') {
3774 reply("NSMSG_TITLE_INVALID");
3778 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
3779 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3781 reply("NSMSG_TITLE_TRUNCATED");
3785 hi
->fakehost
= malloc(strlen(title
)+2);
3786 hi
->fakehost
[0] = '.';
3787 strcpy(hi
->fakehost
+1, title
);
3790 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3791 title
= hi
->fakehost
+ 1;
3793 /* If theres no title set then the default title will therefore
3794 be the first part of hidden_host in x3.conf, so for
3795 consistency with opt_fakehost we will print this here.
3796 This isnt actually used in P10, its just handled to keep from crashing... */
3797 char *hs
, *hidden_suffix
, *rest
;
3799 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3800 hidden_suffix
= strdup(hs
);
3802 /* Yes we do this twice */
3803 if((rest
= strchr(hidden_suffix
, '.')))
3806 title
= hidden_suffix
;
3810 /* A lame default if someone configured hidden_host to something lame */
3811 title
= strdup("users");
3812 free(hidden_suffix
);
3818 none
= user_find_message(user
, "MSG_NONE");
3820 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3825 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3829 // check for a dot in the vhost
3830 if(strchr(vhost
, '.') == NULL
) {
3831 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3835 // check for a @ in the vhost
3836 if(strchr(vhost
, '@') != NULL
) {
3837 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3841 // check for denied words, inspired by monk at paki.sex
3842 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3843 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3844 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3849 // check for ircu's HOSTLEN length.
3850 if(strlen(vhost
) >= HOSTLEN
) {
3851 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3855 /* This can be handled by the regex now if desired.
3856 if (vhost[strspn(vhost, "0123456789.")]) {
3857 hostname = vhost + strlen(vhost);
3858 for (depth = 1; depth && (hostname > vhost); depth--) {
3860 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3863 if (*hostname == '.') hostname++; * advance past last dot we saw *
3864 if(strlen(hostname) > 4) {
3865 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3870 /* test either regex or as valid handle */
3871 if (nickserv_conf
.valid_fakehost_regex_set
) {
3872 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3875 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3876 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3878 if(err
== REG_NOMATCH
) {
3879 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3888 static OPTION_FUNC(opt_fakehost
)
3892 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3895 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3900 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3902 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3905 if (!strcmp(fake
, "*")) {
3908 hi
->fakehost
= NULL
;
3911 else if (!check_vhost(argv
[1], user
, cmd
)) {
3912 /* check_vhost takes care of error reply */
3918 hi
->fakehost
= strdup(fake
);
3921 fake
= hi
->fakehost
;
3923 fake
= generate_fakehost(hi
);
3925 /* Tell them we set the host */
3927 fake
= user_find_message(user
, "MSG_NONE");
3929 reply("NSMSG_SET_FAKEHOST", fake
);
3933 static OPTION_FUNC(opt_note
)
3937 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3942 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3947 if ((text
[0] == '*') && !text
[1])
3950 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3956 reply("NSMSG_SET_NOTE", hi
->note
? hi
->note
->note
: user_find_message(user
, "MSG_NONE"));
3960 static NICKSERV_FUNC(cmd_reclaim
)
3962 struct nick_info
*ni
;
3963 struct userNode
*victim
;
3965 NICKSERV_MIN_PARMS(2);
3966 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3968 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3971 if (ni
->owner
!= user
->handle_info
) {
3972 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3975 victim
= GetUserH(ni
->nick
);
3977 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3980 if (victim
== user
) {
3981 reply("NSMSG_NICK_USER_YOU");
3984 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3985 switch (nickserv_conf
.reclaim_action
) {
3986 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3987 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3988 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3989 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3994 static NICKSERV_FUNC(cmd_unregnick
)
3997 struct handle_info
*hi
;
3998 struct nick_info
*ni
;
4000 hi
= user
->handle_info
;
4001 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
4002 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
4004 reply("NSMSG_UNKNOWN_NICK", nick
);
4007 if (hi
!= ni
->owner
) {
4008 reply("NSMSG_NOT_YOUR_NICK", nick
);
4011 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
4016 static NICKSERV_FUNC(cmd_ounregnick
)
4018 struct nick_info
*ni
;
4020 NICKSERV_MIN_PARMS(2);
4021 if (!(ni
= get_nick_info(argv
[1]))) {
4022 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
4025 if (!oper_outranks(user
, ni
->owner
))
4027 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
4032 static NICKSERV_FUNC(cmd_unregister
)
4034 struct handle_info
*hi
;
4037 NICKSERV_MIN_PARMS(2);
4038 hi
= user
->handle_info
;
4041 if (checkpass(passwd
, hi
->passwd
)) {
4042 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
4047 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
4048 reply("NSMSG_PASSWORD_INVALID");
4053 static NICKSERV_FUNC(cmd_ounregister
)
4055 struct handle_info
*hi
;
4056 char reason
[MAXLEN
];
4059 NICKSERV_MIN_PARMS(2);
4060 if (!(hi
= get_victim_oper(user
, argv
[1])))
4063 if (HANDLE_FLAGGED(hi
, NODELETE
)) {
4064 reply("NSMSG_UNREGISTER_NODELETE", hi
->handle
);
4068 force
= IsOper(user
) && (argc
> 2) && !irccasecmp(argv
[2], "force");
4070 ((hi
->flags
& nickserv_conf
.ounregister_flags
)
4072 || (hi
->last_quit_host
[0] && ((unsigned)(now
- hi
->lastseen
) < nickserv_conf
.ounregister_inactive
)))) {
4073 reply((IsOper(user
) ? "NSMSG_UNREGISTER_MUST_FORCE" : "NSMSG_UNREGISTER_CANNOT_FORCE"), hi
->handle
);
4076 snprintf(reason
, sizeof(reason
), "%s unregistered account %s.", user
->handle_info
->handle
, hi
->handle
);
4077 global_message(MESSAGE_RECIPIENT_STAFF
, reason
);
4078 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
4084 static NICKSERV_FUNC(cmd_status
)
4086 if (nickserv_conf
.disable_nicks
) {
4087 reply("NSMSG_GLOBAL_STATS_NONICK",
4088 dict_size(nickserv_handle_dict
));
4090 if (user
->handle_info
) {
4092 struct nick_info
*ni
;
4093 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
4094 reply("NSMSG_HANDLE_STATS", cnt
);
4096 reply("NSMSG_HANDLE_NONE");
4098 reply("NSMSG_GLOBAL_STATS",
4099 dict_size(nickserv_handle_dict
),
4100 dict_size(nickserv_nick_dict
));
4105 static NICKSERV_FUNC(cmd_ghost
)
4107 struct userNode
*target
;
4108 char reason
[MAXLEN
];
4110 NICKSERV_MIN_PARMS(2);
4111 if (!(target
= GetUserH(argv
[1]))) {
4112 reply("MSG_NICK_UNKNOWN", argv
[1]);
4115 if (target
== user
) {
4116 reply("NSMSG_CANNOT_GHOST_SELF");
4119 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
4120 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
4123 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
4124 DelUser(target
, nickserv
, 1, reason
);
4125 reply("NSMSG_GHOST_KILLED", argv
[1]);
4129 static NICKSERV_FUNC(cmd_vacation
)
4131 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
4132 reply("NSMSG_ON_VACATION");
4137 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
4139 struct handle_info
*hi
;
4142 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
4144 saxdb_start_record(ctx
, iter_key(it
), 0);
4145 if (hi
->announcements
!= '?') {
4146 flags
[0] = hi
->announcements
;
4148 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
4151 struct handle_cookie
*cookie
= hi
->cookie
;
4154 switch (cookie
->type
) {
4155 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
4156 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
4157 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
4158 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
4159 default: type
= NULL
; break;
4162 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
4163 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
4164 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
4166 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
4167 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
4168 saxdb_end_record(ctx
);
4172 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
4174 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
4176 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
4177 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
4178 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
4179 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
4180 saxdb_end_record(ctx
);
4184 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
4188 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
4189 if (hi
->flags
& (1 << ii
))
4190 flags
[flen
++] = handle_flags
[ii
];
4192 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
4195 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
4196 if (hi
->last_quit_host
[0])
4197 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
4198 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
4200 saxdb_write_sint(ctx
, KEY_KARMA
, hi
->karma
);
4201 if (hi
->masks
->used
)
4202 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
4203 if (hi
->sslfps
->used
)
4204 saxdb_write_string_list(ctx
, KEY_SSLFPS
, hi
->sslfps
);
4205 if (hi
->ignores
->used
)
4206 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
4208 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
4210 struct nick_info
*ni
;
4212 saxdb_start_record(ctx
, KEY_NICKS_EX
, 0);
4213 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
4214 saxdb_start_record(ctx
, ni
->nick
, 0);
4215 saxdb_write_int(ctx
, KEY_REGISTER_ON
, ni
->registered
);
4216 saxdb_write_int(ctx
, KEY_LAST_SEEN
, ni
->lastseen
);
4217 saxdb_end_record(ctx
);
4219 saxdb_end_record(ctx
);
4221 if (hi
->opserv_level
)
4222 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
4223 if (hi
->language
!= lang_C
)
4224 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
4225 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
4226 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
4227 if (hi
->screen_width
)
4228 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
4229 if (hi
->table_width
)
4230 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
4231 flags
[0] = hi
->userlist_style
;
4233 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
4234 saxdb_end_record(ctx
);
4240 static handle_merge_func_t
*handle_merge_func_list
;
4241 static void **handle_merge_func_list_extra
;
4242 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
4245 reg_handle_merge_func(handle_merge_func_t func
, void *extra
)
4247 if (handle_merge_func_used
== handle_merge_func_size
) {
4248 if (handle_merge_func_size
) {
4249 handle_merge_func_size
<<= 1;
4250 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
4251 handle_merge_func_list_extra
= realloc(handle_merge_func_list_extra
, handle_merge_func_size
*sizeof(void*));
4253 handle_merge_func_size
= 8;
4254 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
4255 handle_merge_func_list_extra
= malloc(handle_merge_func_size
*sizeof(void*));
4258 handle_merge_func_list
[handle_merge_func_used
] = func
;
4259 handle_merge_func_list_extra
[handle_merge_func_used
++] = extra
;
4262 static NICKSERV_FUNC(cmd_merge
)
4264 struct handle_info
*hi_from
, *hi_to
;
4265 struct userNode
*last_user
;
4266 struct userData
*cList
, *cListNext
;
4267 unsigned int ii
, jj
, n
;
4269 NICKSERV_MIN_PARMS(3);
4271 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
4273 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
4275 if (hi_to
== hi_from
) {
4276 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
4280 for (n
=0; n
<handle_merge_func_used
; n
++)
4281 handle_merge_func_list
[n
](user
, hi_to
, hi_from
, handle_merge_func_list_extra
[n
]);
4283 /* Append "from" handle's nicks to "to" handle's nick list. */
4285 struct nick_info
*last_ni
;
4286 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
4287 last_ni
->next
= hi_from
->nicks
;
4289 while (hi_from
->nicks
) {
4290 hi_from
->nicks
->owner
= hi_to
;
4291 hi_from
->nicks
= hi_from
->nicks
->next
;
4294 /* Merge the hostmasks. */
4295 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
4296 char *mask
= hi_from
->masks
->list
[ii
];
4297 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
4298 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
4300 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
4301 string_list_append(hi_to
->masks
, strdup(mask
));
4304 /* Merge the SSL fingerprints. */
4305 for (ii
=0; ii
<hi_from
->sslfps
->used
; ii
++) {
4306 char *sslfp
= hi_from
->sslfps
->list
[ii
];
4307 for (jj
=0; jj
<hi_to
->sslfps
->used
; jj
++)
4308 if (!irccasecmp(hi_to
->sslfps
->list
[jj
], sslfp
))
4310 if (jj
==hi_to
->sslfps
->used
) /* Nothing from the "to" handle covered this sslfp, so add it. */
4311 string_list_append(hi_to
->sslfps
, strdup(sslfp
));
4314 /* Merge the ignores. */
4315 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
4316 char *ignore
= hi_from
->ignores
->list
[ii
];
4317 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
4318 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
4320 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
4321 string_list_append(hi_to
->ignores
, strdup(ignore
));
4324 /* Merge the lists of authed users. */
4326 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
4327 last_user
->next_authed
= hi_from
->users
;
4329 hi_to
->users
= hi_from
->users
;
4331 /* Repoint the old "from" handle's users. */
4332 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
4333 last_user
->handle_info
= hi_to
;
4335 hi_from
->users
= NULL
;
4337 /* Merge channel userlists. */
4338 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
4339 struct userData
*cList2
;
4340 cListNext
= cList
->u_next
;
4341 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
4342 if (cList
->channel
== cList2
->channel
)
4344 if (cList2
&& (cList2
->access
>= cList
->access
)) {
4345 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
);
4346 /* keep cList2 in hi_to; remove cList from hi_from */
4347 del_channel_user(cList
, 1);
4350 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
);
4351 /* remove the lower-ranking cList2 from hi_to */
4352 del_channel_user(cList2
, 1);
4354 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
4356 /* cList needs to be moved from hi_from to hi_to */
4357 cList
->handle
= hi_to
;
4358 /* Remove from linked list for hi_from */
4359 assert(!cList
->u_prev
);
4360 hi_from
->channels
= cList
->u_next
;
4362 cList
->u_next
->u_prev
= cList
->u_prev
;
4363 /* Add to linked list for hi_to */
4364 cList
->u_prev
= NULL
;
4365 cList
->u_next
= hi_to
->channels
;
4366 if (hi_to
->channels
)
4367 hi_to
->channels
->u_prev
= cList
;
4368 hi_to
->channels
= cList
;
4372 /* Do they get an OpServ level promotion? */
4373 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
4374 hi_to
->opserv_level
= hi_from
->opserv_level
;
4376 /* What about last seen time? */
4377 if (hi_from
->lastseen
> hi_to
->lastseen
)
4378 hi_to
->lastseen
= hi_from
->lastseen
;
4380 /* New karma is the sum of the two original karmas. */
4381 hi_to
->karma
+= hi_from
->karma
;
4383 /* Does a fakehost carry over? (This intentionally doesn't set it
4384 * for users previously attached to hi_to. They'll just have to
4387 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
4388 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
4390 /* Notify of success. */
4391 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
4392 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
4393 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
4395 /* Unregister the "from" handle. */
4396 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
4397 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
4398 * the process isn't completed.
4404 struct nickserv_discrim
{
4405 unsigned long flags_on
, flags_off
;
4406 time_t min_registered
, max_registered
;
4409 int min_level
, max_level
;
4410 int min_karma
, max_karma
;
4411 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
4412 const char *nickmask
;
4413 const char *hostmask
;
4414 const char *handlemask
;
4415 const char *emailmask
;
4416 const char *titlemask
;
4417 const char *setwhat
;
4421 unsigned int inldap
;
4425 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
, struct nickserv_discrim
*discrim
);
4427 struct discrim_apply_info
{
4428 struct nickserv_discrim
*discrim
;
4429 discrim_search_func func
;
4430 struct userNode
*source
;
4431 unsigned int matched
;
4434 static struct nickserv_discrim
*
4435 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
4438 struct nickserv_discrim
*discrim
;
4440 discrim
= malloc(sizeof(*discrim
));
4441 memset(discrim
, 0, sizeof(*discrim
));
4442 discrim
->min_level
= 0;
4443 discrim
->max_level
= INT_MAX
;
4444 discrim
->limit
= 50;
4445 discrim
->min_registered
= 0;
4446 discrim
->max_registered
= INT_MAX
;
4447 discrim
->lastseen
= LONG_MAX
;
4448 discrim
->min_karma
= INT_MIN
;
4449 discrim
->max_karma
= INT_MAX
;
4452 discrim
->inldap
= 2;
4455 for (i
=0; i
<argc
; i
++) {
4456 if (i
== argc
- 1) {
4457 reply("MSG_MISSING_PARAMS", argv
[i
]);
4460 if (!irccasecmp(argv
[i
], "limit")) {
4461 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
4462 } else if (!irccasecmp(argv
[i
], "flags")) {
4463 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
4464 } else if (!irccasecmp(argv
[i
], "registered")) {
4465 const char *cmp
= argv
[++i
];
4466 if (cmp
[0] == '<') {
4467 if (cmp
[1] == '=') {
4468 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
4470 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
4472 } else if (cmp
[0] == '=') {
4473 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
4474 } else if (cmp
[0] == '>') {
4475 if (cmp
[1] == '=') {
4476 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
4478 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
4481 reply("MSG_INVALID_CRITERIA", cmp
);
4483 } else if (!irccasecmp(argv
[i
], "seen")) {
4484 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
4485 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
4486 discrim
->nickmask
= argv
[++i
];
4487 } else if (!irccasecmp(argv
[i
], "setwhat")) {
4488 discrim
->setwhat
= argv
[++i
];
4489 if (!(dict_find(nickserv_opt_dict
, discrim
->setwhat
, NULL
))) {
4490 reply("NSMSG_INVALID_OPTION", discrim
->setwhat
);
4493 } else if (!irccasecmp(argv
[i
], "setvalue")) {
4494 discrim
->setval
= argv
[++i
];
4495 } else if (!irccasecmp(argv
[i
], "hostmask")) {
4497 if (!irccasecmp(argv
[i
], "exact")) {
4498 if (i
== argc
- 1) {
4499 reply("MSG_MISSING_PARAMS", argv
[i
]);
4502 discrim
->hostmask_type
= EXACT
;
4503 } else if (!irccasecmp(argv
[i
], "subset")) {
4504 if (i
== argc
- 1) {
4505 reply("MSG_MISSING_PARAMS", argv
[i
]);
4508 discrim
->hostmask_type
= SUBSET
;
4509 } else if (!irccasecmp(argv
[i
], "superset")) {
4510 if (i
== argc
- 1) {
4511 reply("MSG_MISSING_PARAMS", argv
[i
]);
4514 discrim
->hostmask_type
= SUPERSET
;
4515 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
4516 if (i
== argc
- 1) {
4517 reply("MSG_MISSING_PARAMS", argv
[i
]);
4520 discrim
->hostmask_type
= LASTQUIT
;
4523 discrim
->hostmask_type
= SUPERSET
;
4525 discrim
->hostmask
= argv
[++i
];
4526 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask") || !irccasecmp(argv
[i
], "account")) {
4527 if (!irccasecmp(argv
[++i
], "*")) {
4528 discrim
->handlemask
= 0;
4530 discrim
->handlemask
= argv
[i
];
4532 } else if (!irccasecmp(argv
[i
], "email")) {
4533 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
4534 reply("MSG_NO_SEARCH_ACCESS", "email");
4536 } else if (!irccasecmp(argv
[++i
], "*")) {
4537 discrim
->emailmask
= 0;
4539 discrim
->emailmask
= argv
[i
];
4541 } else if (!irccasecmp(argv
[i
], "title")) {
4542 if (!irccasecmp(argv
[++i
], "*")) {
4543 discrim
->titlemask
= 0;
4545 discrim
->titlemask
= argv
[i
];
4547 } else if (!irccasecmp(argv
[i
], "access")) {
4548 const char *cmp
= argv
[++i
];
4549 if (cmp
[0] == '<') {
4550 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
4551 if (cmp
[1] == '=') {
4552 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
4554 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
4556 } else if (cmp
[0] == '=') {
4557 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
4558 } else if (cmp
[0] == '>') {
4559 if (cmp
[1] == '=') {
4560 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
4562 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
4565 reply("MSG_INVALID_CRITERIA", cmp
);
4567 } else if (!irccasecmp(argv
[i
], "karma")) {
4568 const char *cmp
= argv
[++i
];
4569 if (cmp
[0] == '<') {
4570 if (cmp
[1] == '=') {
4571 discrim
->max_karma
= strtoul(cmp
+2, NULL
, 0);
4573 discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0) - 1;
4575 } else if (cmp
[0] == '=') {
4576 discrim
->min_karma
= discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0);
4577 } else if (cmp
[0] == '>') {
4578 if (cmp
[1] == '=') {
4579 discrim
->min_karma
= strtoul(cmp
+2, NULL
, 0);
4581 discrim
->min_karma
= strtoul(cmp
+1, NULL
, 0) + 1;
4584 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
4587 } else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[i
], "inldap")) {
4589 if(true_string(argv
[i
])) {
4590 discrim
->inldap
= 1;
4592 else if (false_string(argv
[i
])) {
4593 discrim
->inldap
= 0;
4596 reply("MSG_INVALID_BINARY", argv
[i
]);
4600 reply("MSG_INVALID_CRITERIA", argv
[i
]);
4611 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
4615 if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
4616 title
= hi
->fakehost
+ 1;
4618 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
4619 || (discrim
->flags_off
& hi
->flags
)
4620 || (discrim
->min_registered
> hi
->registered
)
4621 || (discrim
->max_registered
< hi
->registered
)
4622 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
4623 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
4624 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
4625 || (discrim
->titlemask
&& (!title
|| !match_ircglob(title
, discrim
->titlemask
)))
4626 || (discrim
->min_level
> hi
->opserv_level
)
4627 || (discrim
->max_level
< hi
->opserv_level
)
4628 || (discrim
->min_karma
> hi
->karma
)
4629 || (discrim
->max_karma
< hi
->karma
)
4633 if (discrim
->hostmask
) {
4635 for (i
=0; i
<hi
->masks
->used
; i
++) {
4636 const char *mask
= hi
->masks
->list
[i
];
4637 if ((discrim
->hostmask_type
== SUBSET
)
4638 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
4639 else if ((discrim
->hostmask_type
== EXACT
)
4640 && !irccasecmp(discrim
->hostmask
, mask
)) break;
4641 else if ((discrim
->hostmask_type
== SUPERSET
)
4642 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
4643 else if ((discrim
->hostmask_type
== LASTQUIT
)
4644 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
4646 if (i
==hi
->masks
->used
) return 0;
4648 if (discrim
->nickmask
) {
4649 struct nick_info
*nick
= hi
->nicks
;
4651 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
4654 if (!nick
) return 0;
4657 if(nickserv_conf
.ldap_enable
&& discrim
->inldap
!= 2) {
4659 rc
= ldap_get_user_info(hi
->handle
, NULL
);
4660 if(discrim
->inldap
== 1 && rc
!= LDAP_SUCCESS
)
4662 if(discrim
->inldap
== 0 && rc
== LDAP_SUCCESS
)
4671 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
4673 dict_iterator_t it
, next
;
4674 unsigned int matched
;
4676 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
4677 it
&& (matched
< discrim
->limit
);
4679 next
= iter_next(it
);
4680 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
4681 dsf(source
, iter_data(it
), discrim
);
4689 search_print_func(struct userNode
*source
, struct handle_info
*match
, UNUSED_ARG(struct nickserv_discrim
*discrim
))
4691 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
4695 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
), UNUSED_ARG(struct nickserv_discrim
*discrim
))
4700 search_unregister_func (struct userNode
*source
, struct handle_info
*match
, UNUSED_ARG(struct nickserv_discrim
*discrim
))
4702 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
4703 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
4708 search_add2ldap_func (struct userNode
*source
, struct handle_info
*match
, UNUSED_ARG(struct nickserv_discrim
*discrim
))
4711 if(match
->email_addr
&& match
->passwd
&& match
->handle
) {
4712 rc
= ldap_do_add(match
->handle
, match
->passwd
, match
->email_addr
);
4713 if(rc
!= LDAP_SUCCESS
) {
4714 send_message(source
, nickserv
, "NSMSG_LDAP_FAIL_ADD", match
->handle
, ldap_err2string(rc
));
4721 search_set_func (struct userNode
*source
, struct handle_info
*match
, struct nickserv_discrim
*discrim
)
4726 if (!(opt
= dict_find(nickserv_opt_dict
, discrim
->setwhat
, NULL
))) {
4730 oargv
[0] = (char *)discrim
->setwhat
;
4731 oargv
[1] = (char *)discrim
->setval
;
4733 opt(discrim
->cmd
, source
, match
, 1, 1, 2, oargv
);
4737 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
4739 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
4740 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
4741 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
4742 return hi_b
->opserv_level
- hi_a
->opserv_level
;
4743 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
4747 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
4749 struct handle_info_list hil
;
4750 struct helpfile_table tbl
;
4755 memset(&hil
, 0, sizeof(hil
));
4756 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
4757 struct handle_info
*hi
= iter_data(it
);
4758 if (hi
->opserv_level
)
4759 handle_info_list_append(&hil
, hi
);
4761 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
4762 tbl
.length
= hil
.used
+ 1;
4764 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
4765 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
4766 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4769 for (ii
= 0; ii
< hil
.used
; ) {
4770 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4771 ary
[0] = hil
.list
[ii
]->handle
;
4772 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
4773 tbl
.contents
[++ii
] = ary
;
4775 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4776 /*reply("MSG_MATCH_COUNT", hil.used); */
4777 for (ii
= 0; ii
< hil
.used
; ii
++)
4778 free(tbl
.contents
[ii
]);
4783 static NICKSERV_FUNC(cmd_search
)
4785 struct nickserv_discrim
*discrim
;
4786 discrim_search_func action
;
4787 struct svccmd
*subcmd
;
4788 unsigned int matches
;
4791 NICKSERV_MIN_PARMS(3);
4792 sprintf(buf
, "search %s", argv
[1]);
4793 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
4794 if (!irccasecmp(argv
[1], "print"))
4795 action
= search_print_func
;
4796 else if (!irccasecmp(argv
[1], "count"))
4797 action
= search_count_func
;
4798 else if (!irccasecmp(argv
[1], "unregister"))
4799 action
= search_unregister_func
;
4800 else if (!irccasecmp(argv
[1], "set"))
4801 action
= search_set_func
;
4803 else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[1], "add2ldap"))
4804 action
= search_add2ldap_func
;
4807 reply("NSMSG_INVALID_ACTION", argv
[1]);
4811 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
4814 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
4818 if (action
== search_print_func
)
4819 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4820 else if (action
== search_count_func
)
4821 discrim
->limit
= INT_MAX
;
4822 else if ((action
== search_set_func
) && (!(discrim
->setwhat
) || !(discrim
->setval
)))
4823 return reply("MSG_MISSING_PARAMS", argv
[1]);
4825 matches
= nickserv_discrim_search(discrim
, action
, user
);
4828 reply("MSG_MATCH_COUNT", matches
);
4830 reply("MSG_NO_MATCHES");
4836 static MODCMD_FUNC(cmd_checkpass
)
4838 struct handle_info
*hi
;
4840 NICKSERV_MIN_PARMS(3);
4841 if (!(hi
= get_handle_info(argv
[1]))) {
4842 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
4845 if (checkpass(argv
[2], hi
->passwd
))
4846 reply("CHECKPASS_YES");
4848 reply("CHECKPASS_NO");
4853 static MODCMD_FUNC(cmd_checkemail
)
4855 struct handle_info
*hi
;
4857 NICKSERV_MIN_PARMS(3);
4858 if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
4861 if (!hi
->email_addr
)
4862 reply("CHECKEMAIL_NOT_SET");
4863 else if (!irccasecmp(argv
[2], hi
->email_addr
))
4864 reply("CHECKEMAIL_YES");
4866 reply("CHECKEMAIL_NO");
4871 nickserv_db_read_handle(char *handle
, dict_t obj
)
4874 struct string_list
*masks
, *sslfps
, *slist
, *ignores
;
4875 struct handle_info
*hi
;
4876 struct userNode
*authed_users
;
4877 struct userData
*channel_list
;
4880 unsigned long int id
;
4883 char *setter
, *note
;
4886 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
4887 id
= str
? strtoul(str
, NULL
, 0) : 0;
4888 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
4890 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
4893 if ((hi
= get_handle_info(handle
))) {
4894 authed_users
= hi
->users
;
4895 channel_list
= hi
->channels
;
4897 hi
->channels
= NULL
;
4898 dict_remove(nickserv_handle_dict
, hi
->handle
);
4900 authed_users
= NULL
;
4901 channel_list
= NULL
;
4903 if(nickserv_conf
.force_handles_lowercase
)
4904 irc_strtolower(handle
);
4905 hi
= register_handle(handle
, str
, id
);
4907 hi
->users
= authed_users
;
4908 while (authed_users
) {
4909 authed_users
->handle_info
= hi
;
4910 authed_users
= authed_users
->next_authed
;
4913 hi
->channels
= channel_list
;
4914 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
4915 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
4916 sslfps
= database_get_data(obj
, KEY_SSLFPS
, RECDB_STRING_LIST
);
4917 hi
->sslfps
= sslfps
? string_list_copy(sslfps
) : alloc_string_list(1);
4918 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
4919 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
4920 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
4921 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
4922 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
4923 hi
->language
= language_find(str
? str
: "C");
4924 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
4925 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
4926 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
4928 hi
->infoline
= strdup(str
);
4929 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
4930 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4931 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
4932 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
4933 str
= database_get_data(obj
, KEY_KARMA
, RECDB_QSTRING
);
4934 hi
->karma
= str
? strtoul(str
, NULL
, 0) : 0;
4935 /* We want to read the nicks even if disable_nicks is set. This is so
4936 * that we don't lose the nick data entirely. */
4937 obj2
= database_get_data(obj
, KEY_NICKS_EX
, RECDB_OBJECT
);
4938 for(it
= dict_first(obj2
); it
; it
= iter_next(it
))
4940 struct record_data
*rd
= iter_data(it
);
4941 struct nick_info
* ni
;
4943 register_nick(iter_key(it
), hi
);
4944 ni
= get_nick_info(iter_key(it
));
4949 str
= database_get_data(rd
->d
.object
, KEY_REGISTER_ON
, RECDB_QSTRING
);
4950 ni
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4951 str
= database_get_data(rd
->d
.object
, KEY_LAST_SEEN
, RECDB_QSTRING
);
4952 ni
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : ni
->registered
;
4955 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
4957 for (ii
=0; ii
<slist
->used
; ii
++) {
4958 struct nick_info
* ni
;
4960 register_nick(slist
->list
[ii
], hi
);
4961 ni
= get_nick_info(slist
->list
[ii
]);
4966 ni
->registered
= hi
->registered
;
4967 ni
->lastseen
= ni
->registered
;
4971 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
4973 for (ii
=0; str
[ii
]; ii
++)
4974 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
4976 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
4977 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4978 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
4979 hi
->announcements
= str
? str
[0] : '?';
4980 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
4981 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
4982 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
4983 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
4984 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
4986 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
4988 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
4989 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
4991 nickserv_set_email_addr(hi
, str
);
4992 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
4994 hi
->epithet
= strdup(str
);
4995 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
4997 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
4998 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
4999 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
5000 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
5001 if (setter
&& date
&& note
)
5003 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
5008 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
5010 hi
->fakehost
= strdup(str
);
5012 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
5014 const char *data
, *type
, *expires
, *cookie_str
;
5015 struct handle_cookie
*cookie
;
5017 cookie
= calloc(1, sizeof(*cookie
));
5018 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
5019 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
5020 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
5021 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
5022 if (!type
|| !expires
|| !cookie_str
) {
5023 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
5026 if (!irccasecmp(type
, KEY_ACTIVATION
))
5027 cookie
->type
= ACTIVATION
;
5028 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
5029 cookie
->type
= PASSWORD_CHANGE
;
5030 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
5031 cookie
->type
= EMAIL_CHANGE
;
5032 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
5033 cookie
->type
= ALLOWAUTH
;
5035 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
5038 cookie
->expires
= strtoul(expires
, NULL
, 0);
5039 if (cookie
->expires
< now
)
5042 cookie
->data
= strdup(data
);
5043 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
5047 nickserv_bake_cookie(cookie
);
5049 nickserv_free_cookie(cookie
);
5054 nickserv_saxdb_read(dict_t db
) {
5056 struct record_data
*rd
;
5059 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
5061 handle
= strdup(iter_key(it
));
5062 nickserv_db_read_handle(handle
, rd
->d
.object
);
5068 static NICKSERV_FUNC(cmd_mergedb
)
5070 struct timeval start
, stop
;
5073 NICKSERV_MIN_PARMS(2);
5074 gettimeofday(&start
, NULL
);
5075 if (!(db
= parse_database(argv
[1]))) {
5076 reply("NSMSG_DB_UNREADABLE", argv
[1]);
5079 nickserv_saxdb_read(db
);
5081 gettimeofday(&stop
, NULL
);
5082 stop
.tv_sec
-= start
.tv_sec
;
5083 stop
.tv_usec
-= start
.tv_usec
;
5084 if (stop
.tv_usec
< 0) {
5086 stop
.tv_usec
+= 1000000;
5088 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
5093 expire_handles(UNUSED_ARG(void *data
))
5095 dict_iterator_t it
, next
;
5097 struct handle_info
*hi
;
5099 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
5100 next
= iter_next(it
);
5102 if ((hi
->opserv_level
> 0)
5104 || HANDLE_FLAGGED(hi
, FROZEN
)
5105 || HANDLE_FLAGGED(hi
, NODELETE
)) {
5108 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
5109 if ((now
- hi
->lastseen
) > expiry
) {
5110 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
5111 nickserv_unregister_handle(hi
, NULL
, NULL
);
5115 if (nickserv_conf
.handle_expire_frequency
)
5116 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
5120 expire_nicks(UNUSED_ARG(void *data
))
5122 dict_iterator_t it
, next
;
5123 time_t expiry
= nickserv_conf
.nick_expire_delay
;
5124 struct nick_info
*ni
;
5125 struct userNode
*ui
;
5127 if (!(nickserv_conf
.expire_nicks
))
5130 for (it
=dict_first(nickserv_nick_dict
); it
; it
=next
) {
5131 next
= iter_next(it
);
5133 if ((ni
->owner
->opserv_level
> 0)
5134 || ((ui
= GetUserH(ni
->nick
)) && (ui
->handle_info
) && (ui
->handle_info
== ni
->owner
))
5135 || HANDLE_FLAGGED(ni
->owner
, FROZEN
)
5136 || HANDLE_FLAGGED(ni
->owner
, NODELETE
)) {
5139 if ((now
- ni
->lastseen
) > expiry
) {
5140 log_module(NS_LOG
, LOG_INFO
, "Expiring nick %s for inactivity.", ni
->nick
);
5145 if (nickserv_conf
.nick_expire_frequency
&& nickserv_conf
.expire_nicks
)
5146 timeq_add(now
+ nickserv_conf
.nick_expire_frequency
, expire_nicks
, NULL
);
5150 nickserv_load_dict(const char *fname
)
5154 if (!(file
= fopen(fname
, "r"))) {
5155 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
5158 while (fgets(line
, sizeof(line
), file
)) {
5161 if (line
[strlen(line
)-1] == '\n')
5162 line
[strlen(line
)-1] = 0;
5163 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
5166 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
5169 static enum reclaim_action
5170 reclaim_action_from_string(const char *str
) {
5172 return RECLAIM_NONE
;
5173 else if (!irccasecmp(str
, "warn"))
5174 return RECLAIM_WARN
;
5175 else if (!irccasecmp(str
, "svsnick"))
5176 return RECLAIM_SVSNICK
;
5177 else if (!irccasecmp(str
, "kill"))
5178 return RECLAIM_KILL
;
5180 return RECLAIM_NONE
;
5184 nickserv_conf_read(void)
5186 dict_t conf_node
, child
;
5189 struct string_list
*strlist
;
5191 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
5192 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
5195 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
5197 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
5198 if (nickserv_conf
.valid_handle_regex_set
)
5199 regfree(&nickserv_conf
.valid_handle_regex
);
5201 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
5202 nickserv_conf
.valid_handle_regex_set
= !err
;
5203 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
5205 nickserv_conf
.valid_handle_regex_set
= 0;
5207 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
5208 if (nickserv_conf
.valid_nick_regex_set
)
5209 regfree(&nickserv_conf
.valid_nick_regex
);
5211 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
5212 nickserv_conf
.valid_nick_regex_set
= !err
;
5213 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
5215 nickserv_conf
.valid_nick_regex_set
= 0;
5217 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
5218 if (nickserv_conf
.valid_fakehost_regex_set
)
5219 regfree(&nickserv_conf
.valid_fakehost_regex
);
5221 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
5222 nickserv_conf
.valid_fakehost_regex_set
= !err
;
5223 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
5225 nickserv_conf
.valid_fakehost_regex_set
= 0;
5227 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
5229 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
5230 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
5231 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
5232 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
5233 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
5234 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
5235 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
5236 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
5237 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
5238 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
5239 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
5240 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
5241 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
5242 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
5243 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
5244 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
5245 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
5246 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
5247 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
5248 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
5249 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
5250 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
5251 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
5252 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
5253 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
5255 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
5256 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
5257 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
5259 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
5260 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
5261 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
5263 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
5264 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
5265 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
5266 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
5267 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
5268 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
5269 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
5270 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
5271 str
= database_get_data(conf_node
, KEY_OUNREGISTER_INACTIVE
, RECDB_QSTRING
);
5272 nickserv_conf
.ounregister_inactive
= str
? ParseInterval(str
) : 86400*28;
5273 str
= database_get_data(conf_node
, KEY_OUNREGISTER_FLAGS
, RECDB_QSTRING
);
5276 nickserv_conf
.ounregister_flags
= 0;
5278 unsigned int pos
= handle_inverse_flags
[(unsigned char)*str
];
5281 nickserv_conf
.ounregister_flags
|= 1 << (pos
- 1);
5283 if (!nickserv_conf
.disable_nicks
) {
5284 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
5285 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
5286 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
5287 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
5288 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
5289 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
5290 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
5291 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
5292 str
= database_get_data(conf_node
, KEY_NICK_EXPIRE_FREQ
, RECDB_QSTRING
);
5293 nickserv_conf
.nick_expire_frequency
= str
? ParseInterval(str
) : 86400;
5294 str
= database_get_data(conf_node
, KEY_NICK_EXPIRE_DELAY
, RECDB_QSTRING
);
5295 nickserv_conf
.nick_expire_delay
= str
? ParseInterval(str
) : 86400*30;
5296 str
= database_get_data(conf_node
, "expire_nicks", RECDB_QSTRING
);
5297 nickserv_conf
.expire_nicks
= str
? enabled_string(str
) : 0;
5299 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
5300 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
5301 const char *key
= iter_key(it
), *value
;
5305 if (!strncasecmp(key
, "uc_", 3))
5306 flag
= toupper(key
[3]);
5307 else if (!strncasecmp(key
, "lc_", 3))
5308 flag
= tolower(key
[3]);
5312 if ((pos
= handle_inverse_flags
[flag
])) {
5313 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
5314 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
5317 if (nickserv_conf
.weak_password_dict
)
5318 dict_delete(nickserv_conf
.weak_password_dict
);
5319 nickserv_conf
.weak_password_dict
= dict_new();
5320 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
5321 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
5322 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
5323 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
5325 nickserv_load_dict(str
);
5326 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
5327 if (nickserv
&& str
)
5328 NickChange(nickserv
, str
, 0);
5329 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
5330 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
5331 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
5332 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
5333 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
5334 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
5335 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
5336 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
5337 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
5338 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
5339 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
5340 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
5341 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
5342 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
5343 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
5344 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
5345 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
5346 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
5347 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
5348 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
5350 free_string_list(nickserv_conf
.denied_fakehost_words
);
5351 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
5353 strlist
= string_list_copy(strlist
);
5355 strlist
= alloc_string_list(4);
5356 string_list_append(strlist
, strdup("sex"));
5357 string_list_append(strlist
, strdup("fuck"));
5359 nickserv_conf
.denied_fakehost_words
= strlist
;
5361 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
5362 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
5364 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
5365 nickserv_conf
.auto_oper
= str
? str
: "";
5367 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
5368 nickserv_conf
.auto_admin
= str
? str
: "";
5370 str
= database_get_data(conf_node
, KEY_AUTO_OPER_PRIVS
, RECDB_QSTRING
);
5371 nickserv_conf
.auto_oper_privs
= str
? str
: "";
5373 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN_PRIVS
, RECDB_QSTRING
);
5374 nickserv_conf
.auto_admin_privs
= str
? str
: "";
5376 str
= conf_get_data("server/network", RECDB_QSTRING
);
5377 nickserv_conf
.network_name
= str
? str
: "some IRC network";
5378 if (!nickserv_conf
.auth_policer_params
) {
5379 nickserv_conf
.auth_policer_params
= policer_params_new();
5380 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
5381 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
5383 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
5384 for (it
=dict_first(child
); it
; it
=iter_next(it
))
5385 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
5387 str
= database_get_data(conf_node
, KEY_LDAP_ENABLE
, RECDB_QSTRING
);
5388 nickserv_conf
.ldap_enable
= str
? strtoul(str
, NULL
, 0) : 0;
5390 str
= database_get_data(conf_node
, KEY_FORCE_HANDLES_LOWERCASE
, RECDB_QSTRING
);
5391 nickserv_conf
.force_handles_lowercase
= str
? strtol(str
, NULL
, 0) : 0;
5394 if(nickserv_conf
.ldap_enable
> 0) {
5395 /* ldap is enabled but not compiled in - error out */
5396 log_module(MAIN_LOG
, LOG_ERROR
, "ldap is enabled in config, but not compiled in!");
5398 /* nickserv_conf.ldap_enable = 0; */
5404 str
= database_get_data(conf_node
, KEY_LDAP_URI
, RECDB_QSTRING
);
5405 nickserv_conf
.ldap_uri
= str
? str
: "";
5407 str
= database_get_data(conf_node
, KEY_LDAP_BASE
, RECDB_QSTRING
);
5408 nickserv_conf
.ldap_base
= str
? str
: "";
5410 str
= database_get_data(conf_node
, KEY_LDAP_DN_FMT
, RECDB_QSTRING
);
5411 nickserv_conf
.ldap_dn_fmt
= str
? str
: "";
5413 str
= database_get_data(conf_node
, KEY_LDAP_VERSION
, RECDB_QSTRING
);
5414 nickserv_conf
.ldap_version
= str
? strtoul(str
, NULL
, 0) : 3;
5416 str
= database_get_data(conf_node
, KEY_LDAP_AUTOCREATE
, RECDB_QSTRING
);
5417 nickserv_conf
.ldap_autocreate
= str
? strtoul(str
, NULL
, 0) : 0;
5419 str
= database_get_data(conf_node
, KEY_LDAP_TIMEOUT
, RECDB_QSTRING
);
5420 nickserv_conf
.ldap_timeout
= str
? strtoul(str
, NULL
, 0) : 5;
5422 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_DN
, RECDB_QSTRING
);
5423 nickserv_conf
.ldap_admin_dn
= str
? str
: "";
5425 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_PASS
, RECDB_QSTRING
);
5426 nickserv_conf
.ldap_admin_pass
= str
? str
: "";
5428 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_ACCOUNT
, RECDB_QSTRING
);
5429 nickserv_conf
.ldap_field_account
= str
? str
: "";
5431 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_PASSWORD
, RECDB_QSTRING
);
5432 nickserv_conf
.ldap_field_password
= str
? str
: "";
5434 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_EMAIL
, RECDB_QSTRING
);
5435 nickserv_conf
.ldap_field_email
= str
? str
: "";
5437 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_OSLEVEL
, RECDB_QSTRING
);
5438 nickserv_conf
.ldap_field_oslevel
= str
? str
: "";
5440 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_DN
, RECDB_QSTRING
);
5441 nickserv_conf
.ldap_oper_group_dn
= str
? str
: "";
5443 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_LEVEL
, RECDB_QSTRING
);
5444 nickserv_conf
.ldap_oper_group_level
= str
? strtoul(str
, NULL
, 0) : 99;
5446 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_GROUP_MEMBER
, RECDB_QSTRING
);
5447 nickserv_conf
.ldap_field_group_member
= str
? str
: "";
5449 free_string_list(nickserv_conf
.ldap_object_classes
);
5450 strlist
= database_get_data(conf_node
, KEY_LDAP_OBJECT_CLASSES
, RECDB_STRING_LIST
);
5452 strlist
= string_list_copy(strlist
);
5454 strlist
= alloc_string_list(4);
5455 string_list_append(strlist
, strdup("top"));
5457 nickserv_conf
.ldap_object_classes
= strlist
;
5464 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
5466 char newnick
[NICKLEN
+1];
5479 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
5480 send_message(user
, nickserv
, "NSMSG_RECLAIM_HOWTO", ni
->owner
->handle
, nickserv
->nick
, self
->name
, ni
->owner
->handle
);
5482 case RECLAIM_SVSNICK
:
5484 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
5485 } while (GetUserH(newnick
));
5486 irc_svsnick(nickserv
, user
, newnick
);
5489 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
5490 DelUser(user
, nickserv
, 1, msg
);
5496 nickserv_reclaim_p(void *data
) {
5497 struct userNode
*user
= data
;
5498 struct nick_info
*ni
= get_nick_info(user
->nick
);
5500 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5504 check_user_nick(struct userNode
*user
, UNUSED_ARG(void *extra
)) {
5505 struct nick_info
*ni
;
5506 user
->modes
&= ~FLAGS_REGNICK
;
5508 if (!(ni
= get_nick_info(user
->nick
)))
5510 if (user
->handle_info
== ni
->owner
) {
5511 user
->modes
|= FLAGS_REGNICK
;
5515 if (nickserv_conf
.warn_nick_owned
) {
5516 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
5517 send_message(user
, nickserv
, "NSMSG_RECLAIM_HOWTO", ni
->owner
->handle
, nickserv
->nick
, self
->name
, ni
->owner
->handle
);
5519 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
5521 if (nickserv_conf
.auto_reclaim_delay
)
5522 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
5524 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5530 new_user_event(struct userNode
*user
, void *extra
) {
5531 /* If the user's server is not bursting,
5532 * the user is authed, the account has autohide set
5533 * and the user doesn't have user mode +x then apply
5534 * the autohide setting.
5536 if (!user
->uplink
->burst
&& user
->handle_info
&&
5537 HANDLE_FLAGGED(user
->handle_info
, AUTOHIDE
) &&
5538 !IsHiddenHost(user
))
5539 irc_umode(user
, "+x");
5541 return check_user_nick(user
, extra
);
5545 handle_account(struct userNode
*user
, const char *stamp
)
5547 struct handle_info
*hi
;
5550 #ifdef WITH_PROTOCOL_P10
5551 time_t timestamp
= 0;
5553 colon
= strchr(stamp
, ':');
5554 if(colon
&& colon
[1])
5557 timestamp
= atoi(colon
+1);
5559 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
5560 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
5562 log_module(MAIN_LOG
, LOG_WARNING
, "%s using account %s but timestamp does not match %s is not %s.", user
->nick
, stamp
, ctime(×tamp
),
5563 ctime(&hi
->registered
));
5567 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
5568 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
5572 if(!hi
&& nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_autocreate
&&
5573 (ldap_user_exists(stamp
) == LDAP_SUCCESS
)) {
5579 /* First attempt to get the email address from LDAP */
5580 if((rc
= ldap_get_user_info(stamp
, &email
) != LDAP_SUCCESS
))
5581 if(nickserv_conf
.email_required
)
5584 /* Now try to register the handle */
5585 if (cont
&& (hi
= nickserv_register(user
, user
, stamp
, NULL
, 1))) {
5586 if(nickserv_conf
.default_hostmask
)
5589 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
5592 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
5593 string_list_append(hi
->masks
, mask_canonicalized
);
5597 nickserv_set_email_addr(hi
, email
);
5605 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
5608 set_user_handle_info(user
, hi
, 0);
5610 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
5615 handle_nick_change(struct userNode
*user
, const char *old_nick
, UNUSED_ARG(void *extra
))
5617 struct handle_info
*hi
;
5619 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
5620 dict_remove(nickserv_allow_auth_dict
, old_nick
);
5621 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
5623 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5624 check_user_nick(user
, NULL
);
5628 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
), UNUSED_ARG(void *extra
))
5630 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
5631 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5632 set_user_handle_info(user
, NULL
, 0);
5635 static struct modcmd
*
5636 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
5638 if (min_level
> 0) {
5640 sprintf(buf
, "%u", min_level
);
5641 if (must_be_qualified
) {
5642 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
5644 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
5646 } else if (min_level
== 0) {
5647 if (must_be_qualified
) {
5648 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5650 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5653 if (must_be_qualified
) {
5654 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
5656 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
5661 #define SDFLAG_STALE 0x01 /**< SASL session data is stale, delete on next pass. */
5665 struct SASLSession
*next
;
5666 struct SASLSession
*prev
;
5667 struct server
* source
;
5677 struct SASLSession
*saslsessions
= NULL
;
5680 sasl_delete_session(struct SASLSession
*session
)
5687 session
->buf
= NULL
;
5689 if (session
->sslclifp
)
5690 free(session
->sslclifp
);
5691 session
->sslclifp
= NULL
;
5693 if (session
->hostmask
)
5694 free(session
->hostmask
);
5695 session
->hostmask
= NULL
;
5698 session
->next
->prev
= session
->prev
;
5700 session
->prev
->next
= session
->next
;
5702 saslsessions
= session
->next
;
5708 sasl_delete_stale(UNUSED_ARG(void *data
))
5712 struct SASLSession
*sess
= NULL
;
5713 struct SASLSession
*nextsess
= NULL
;
5715 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Checking for stale sessions");
5717 for (sess
= saslsessions
; sess
; sess
= nextsess
)
5719 nextsess
= sess
->next
;
5721 if (sess
->flags
& SDFLAG_STALE
)
5724 sasl_delete_session(sess
);
5729 sess
->flags
|= SDFLAG_STALE
;
5734 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Deleted %d stale sessions, %d remaining", delcount
, remcount
);
5736 timeq_add(now
+ 30, sasl_delete_stale
, NULL
);
5740 sasl_get_session(const char *uid
)
5742 struct SASLSession
*sess
;
5744 for (sess
= saslsessions
; sess
; sess
= sess
->next
)
5746 if (!strncmp(sess
->uid
, uid
, 128))
5748 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Found session for %s", sess
->uid
);
5753 sess
= malloc(sizeof(struct SASLSession
));
5754 memset(sess
, 0, sizeof(struct SASLSession
));
5756 strncpy(sess
->uid
, uid
, 128);
5759 timeq_add(now
+ 30, sasl_delete_stale
, NULL
);
5762 saslsessions
->prev
= sess
;
5763 sess
->next
= saslsessions
;
5764 saslsessions
= sess
;
5766 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Created session for %s", sess
->uid
);
5771 sasl_packet(struct SASLSession
*session
)
5773 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Got packet containing: %s", session
->buf
);
5775 if (!session
->mech
[0])
5777 log_module(NS_LOG
, LOG_DEBUG
, "SASL: No mechanism stored yet, using %s", session
->buf
);
5778 if (strcmp(session
->buf
, "PLAIN") && (strcmp(session
->buf
, "EXTERNAL") || !session
->sslclifp
)) {
5779 if (!session
->sslclifp
)
5780 irc_sasl(session
->source
, session
->uid
, "M", "PLAIN");
5782 irc_sasl(session
->source
, session
->uid
, "M", "PLAIN,EXTERNAL");
5783 irc_sasl(session
->source
, session
->uid
, "D", "F");
5784 sasl_delete_session(session
);
5788 strncpy(session
->mech
, session
->buf
, 10);
5789 irc_sasl(session
->source
, session
->uid
, "C", "+");
5791 else if (!strcmp(session
->mech
, "EXTERNAL"))
5795 char *authzid
= NULL
;
5796 struct handle_info
*hi
= NULL
;
5797 static char buffer
[256];
5799 base64_decode_alloc(session
->buf
, session
->buflen
, &raw
, &rawlen
);
5804 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Checking supplied credentials");
5806 if (!session
->sslclifp
) {
5807 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Incomplete credentials supplied");
5808 irc_sasl(session
->source
, session
->uid
, "D", "F");
5810 if (!(hi
= loc_auth(session
->sslclifp
, authzid
, NULL
, session
->hostmask
)))
5812 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Invalid credentials supplied");
5813 irc_sasl(session
->source
, session
->uid
, "D", "F");
5817 snprintf(buffer
, sizeof(buffer
), "%s "FMT_TIME_T
, hi
->handle
, hi
->registered
);
5818 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Valid credentials supplied");
5819 irc_sasl(session
->source
, session
->uid
, "L", buffer
);
5820 irc_sasl(session
->source
, session
->uid
, "D", "S");
5824 sasl_delete_session(session
);
5833 char *authzid
= NULL
;
5834 char *authcid
= NULL
;
5835 char *passwd
= NULL
;
5837 unsigned int i
= 0, c
= 0;
5838 struct handle_info
*hi
= NULL
;
5839 struct handle_info
*hii
= NULL
;
5840 static char buffer
[256];
5842 base64_decode_alloc(session
->buf
, session
->buflen
, &raw
, &rawlen
);
5844 raw
= (char *)realloc(raw
, rawlen
+1);
5849 for (i
=0; i
<rawlen
; i
++)
5860 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Checking supplied credentials");
5862 if ((c
!= 2) || !(*authcid
))
5864 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Incomplete credentials supplied");
5865 irc_sasl(session
->source
, session
->uid
, "D", "F");
5869 if (!(hi
= loc_auth(session
->sslclifp
, authcid
, passwd
, session
->hostmask
)))
5871 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Invalid credentials supplied");
5872 irc_sasl(session
->source
, session
->uid
, "D", "F");
5876 if (*authzid
&& irccasecmp(authzid
, authcid
))
5878 if (HANDLE_FLAGGED(hi
, IMPERSONATE
))
5881 hi
= get_handle_info(authzid
);
5885 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Impersonation unauthorized");
5893 log_module(NS_LOG
, LOG_DEBUG
, "SASL: %s is ipersonating %s", hii
->handle
, hi
->handle
);
5894 snprintf(buffer
, sizeof(buffer
), "%s "FMT_TIME_T
, hii
->handle
, hii
->registered
);
5895 irc_sasl(session
->source
, session
->uid
, "I", buffer
);
5897 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Valid credentials supplied");
5898 snprintf(buffer
, sizeof(buffer
), "%s "FMT_TIME_T
, hi
->handle
, hi
->registered
);
5899 irc_sasl(session
->source
, session
->uid
, "L", buffer
);
5900 irc_sasl(session
->source
, session
->uid
, "D", "S");
5904 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Invalid credentials supplied");
5905 irc_sasl(session
->source
, session
->uid
, "D", "F");
5910 sasl_delete_session(session
);
5916 /* clear stale state */
5917 session
->flags
&= ~SDFLAG_STALE
;
5921 handle_sasl_input(struct server
* source
,const char *uid
, const char *subcmd
, const char *data
, const char *ext
, UNUSED_ARG(void *extra
))
5923 struct SASLSession
* sess
= sasl_get_session(uid
);
5924 int len
= strlen(data
);
5926 sess
->source
= source
;
5928 if (!strcmp(subcmd
, "D"))
5930 sasl_delete_session(sess
);
5934 if (!strcmp(subcmd
, "H")) {
5935 log_module(NS_LOG
, LOG_DEBUG
, "SASL: Storing host mask %s", data
);
5936 sess
->hostmask
= strdup(data
);
5940 if (strcmp(subcmd
, "S") && strcmp(subcmd
, "C"))
5946 if (sess
->p
== NULL
)
5948 sess
->buf
= (char *)malloc(len
+ 1);
5949 sess
->p
= sess
->buf
;
5954 if (sess
->buflen
+ len
+ 1 > 8192) /* This is a little much... */
5956 irc_sasl(source
, uid
, "D", "F");
5957 sasl_delete_session(sess
);
5961 sess
->buf
= (char *)realloc(sess
->buf
, sess
->buflen
+ len
+ 1);
5962 sess
->p
= sess
->buf
+ sess
->buflen
;
5963 sess
->buflen
+= len
;
5966 memcpy(sess
->p
, data
, len
);
5967 sess
->buf
[len
] = '\0';
5970 sess
->sslclifp
= strdup(ext
);
5972 /* Messages not exactly 400 bytes are the end of a packet. */
5977 if (sess
->buf
!= NULL
)
5979 sess
->buf
= sess
->p
= NULL
;
5984 nickserv_db_cleanup(UNUSED_ARG(void* extra
))
5986 unreg_del_user_func(nickserv_remove_user
, NULL
);
5987 unreg_sasl_input_func(handle_sasl_input
, NULL
);
5988 userList_clean(&curr_helpers
);
5989 policer_params_delete(nickserv_conf
.auth_policer_params
);
5990 dict_delete(nickserv_handle_dict
);
5991 dict_delete(nickserv_nick_dict
);
5992 dict_delete(nickserv_opt_dict
);
5993 dict_delete(nickserv_allow_auth_dict
);
5994 dict_delete(nickserv_email_dict
);
5995 dict_delete(nickserv_id_dict
);
5996 dict_delete(nickserv_conf
.weak_password_dict
);
5997 free(auth_func_list
);
5998 free(auth_func_list_extra
);
5999 free(unreg_func_list
);
6000 free(unreg_func_list_extra
);
6002 free(rf_list_extra
);
6003 free(allowauth_func_list
);
6004 free(allowauth_func_list_extra
);
6005 free(handle_merge_func_list
);
6006 free(handle_merge_func_list_extra
);
6007 free(failpw_func_list
);
6008 free(failpw_func_list_extra
);
6009 if (nickserv_conf
.valid_handle_regex_set
)
6010 regfree(&nickserv_conf
.valid_handle_regex
);
6011 if (nickserv_conf
.valid_nick_regex_set
)
6012 regfree(&nickserv_conf
.valid_nick_regex
);
6015 void handle_loc_auth_oper(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
), UNUSED_ARG(void *extra
)) {
6016 char *privv
[MAXNUMPARAMS
];
6019 if (!*nickserv_conf
.auto_oper
|| !user
->handle_info
)
6022 if (!IsOper(user
)) {
6023 if (*nickserv_conf
.auto_admin
&& user
->handle_info
->opserv_level
>= opserv_conf_admin_level()) {
6024 if (nickserv_conf
.auto_admin_privs
[0]) {
6025 irc_raw_privs(user
, nickserv_conf
.auto_admin_privs
);
6026 privc
= split_line(strdup(nickserv_conf
.auto_admin_privs
), false, MAXNUMPARAMS
, privv
);
6027 for (i
= 0; i
< privc
; i
++) {
6028 client_modify_priv_by_name(user
, privv
[i
], 1);
6031 irc_umode(user
, nickserv_conf
.auto_admin
);
6032 irc_sno(0x1, "%s (%s@%s) is now an IRC Administrator",
6033 user
->nick
, user
->ident
, user
->hostname
);
6034 send_message(user
, nickserv
, "NSMSG_AUTO_OPER_ADMIN");
6035 } else if (*nickserv_conf
.auto_oper
&& user
->handle_info
->opserv_level
) {
6036 if (nickserv_conf
.auto_oper_privs
[0]) {
6037 irc_raw_privs(user
, nickserv_conf
.auto_oper_privs
);
6038 privc
= split_line(strdup(nickserv_conf
.auto_oper_privs
), false, MAXNUMPARAMS
, privv
);
6039 for (i
= 0; i
< privc
; i
++) {
6040 client_modify_priv_by_name(user
, privv
[i
], 1);
6043 irc_umode(user
, nickserv_conf
.auto_oper
);
6044 irc_sno(0x1, "%s (%s@%s) is now an IRC Operator",
6045 user
->nick
, user
->ident
, user
->hostname
);
6046 send_message(user
, nickserv
, "NSMSG_AUTO_OPER");
6052 init_nickserv(const char *nick
)
6054 struct chanNode
*chan
;
6056 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
6057 reg_new_user_func(new_user_event
, NULL
);
6058 reg_nick_change_func(handle_nick_change
, NULL
);
6059 reg_del_user_func(nickserv_remove_user
, NULL
);
6060 reg_account_func(handle_account
);
6061 reg_auth_func(handle_loc_auth_oper
, NULL
);
6062 reg_sasl_input_func(handle_sasl_input
, NULL
);
6064 /* set up handle_inverse_flags */
6065 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
6066 for (i
=0; handle_flags
[i
]; i
++) {
6067 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
6068 flag_access_levels
[i
] = 0;
6069 /* ensure flag I requires a minimum of 999 if not set in the config */
6070 if ((unsigned char)handle_flags
[i
] == 'I')
6071 flag_access_levels
[i
] = 999;
6074 conf_register_reload(nickserv_conf_read
);
6075 nickserv_opt_dict
= dict_new();
6076 nickserv_email_dict
= dict_new();
6078 dict_set_free_keys(nickserv_email_dict
, free
);
6079 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
6081 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
6082 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
6083 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
6084 * a big pain to disable since its nolonger in the config file. ) -Rubin
6086 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
6087 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
6088 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
6089 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
6090 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
6091 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
6092 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
6093 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
6094 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
6095 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
6096 nickserv_define_func("ADDCERTFP", cmd_addsslfp
, -1, 1, 0);
6097 nickserv_define_func("OADDCERTFP", cmd_oaddsslfp
, 0, 1, 0);
6098 nickserv_define_func("DELCERTFP", cmd_delsslfp
, -1, 1, 0);
6099 nickserv_define_func("ODELCERTFP", cmd_odelsslfp
, 0, 1, 0);
6100 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
6101 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
6102 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
6103 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
6104 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
6105 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
6106 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
6107 nickserv_define_func("MERGE", cmd_merge
, 750, 1, 0);
6108 if (!nickserv_conf
.disable_nicks
) {
6109 /* nick management commands */
6110 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
6111 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
6112 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
6113 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
6114 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
6115 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
6117 if (nickserv_conf
.email_enabled
) {
6118 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
6119 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
6120 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
6121 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
6122 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
6123 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
6125 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
6126 /* ignore commands */
6127 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
6128 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
6129 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
6130 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
6131 /* miscellaneous commands */
6132 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
6133 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
6134 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
6135 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
6136 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
6137 nickserv_define_func("CHECKEMAIL", cmd_checkemail
, 0, 1, 0);
6139 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
6140 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
6141 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
6142 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
6143 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
6144 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
6145 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
6146 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
6147 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
6148 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
6149 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
6150 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
6151 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
6152 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
6153 if (nickserv_conf
.titlehost_suffix
) {
6154 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
6155 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
6157 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
6158 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
6159 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
6160 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
6161 dict_insert(nickserv_opt_dict
, "KARMA", opt_karma
);
6163 nickserv_handle_dict
= dict_new();
6164 dict_set_free_keys(nickserv_handle_dict
, free
);
6165 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
6167 nickserv_id_dict
= dict_new();
6168 dict_set_free_keys(nickserv_id_dict
, free
);
6170 nickserv_nick_dict
= dict_new();
6171 dict_set_free_data(nickserv_nick_dict
, free
);
6173 nickserv_allow_auth_dict
= dict_new();
6175 userList_init(&curr_helpers
);
6178 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
6179 nickserv
= AddLocalUser(nick
, nick
, NULL
, "Nick Services", modes
);
6180 nickserv_service
= service_register(nickserv
);
6182 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
6183 reg_exit_func(nickserv_db_cleanup
, NULL
);
6184 if(nickserv_conf
.handle_expire_frequency
)
6185 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
6186 if(nickserv_conf
.nick_expire_frequency
&& nickserv_conf
.expire_nicks
)
6187 timeq_add(now
+ nickserv_conf
.nick_expire_frequency
, expire_nicks
, NULL
);
6189 if(autojoin_channels
&& nickserv
) {
6190 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
6191 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
6192 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
6197 ldap_do_init(nickserv_conf
);
6200 message_register_table(msgtab
);