1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
32 #include <tre/regex.h>
38 #define NICKSERV_CONF_NAME "services/nickserv"
40 #define KEY_DISABLE_NICKS "disable_nicks"
41 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
42 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
43 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
44 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
45 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
46 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
47 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
48 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
49 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
50 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
51 #define KEY_VALID_FAKEHOST_REGEX "valid_fakehost_regex"
52 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
53 #define KEY_MODOPER_LEVEL "modoper_level"
54 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
55 #define KEY_SET_TITLE_LEVEL "set_title_level"
56 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
57 #define KEY_DENIED_FAKEHOST_WORDS "denied_fakehost_words"
58 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
59 #define KEY_AUTO_OPER "auto_oper"
60 #define KEY_AUTO_ADMIN "auto_admin"
61 #define KEY_AUTO_OPER_PRIVS "auto_oper_privs"
62 #define KEY_AUTO_ADMIN_PRIVS "auto_admin_privs"
63 #define KEY_FLAG_LEVELS "flag_levels"
64 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
65 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
66 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
67 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
68 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
69 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
70 #define KEY_DICT_FILE "dict_file"
71 #define KEY_NICK "nick"
72 #define KEY_LANGUAGE "language"
73 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
74 #define KEY_AUTOGAG_DURATION "autogag_duration"
75 #define KEY_AUTH_POLICER "auth_policer"
76 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
77 #define KEY_EMAIL_ENABLED "email_enabled"
78 #define KEY_EMAIL_REQUIRED "email_required"
79 #define KEY_SYNC_LOG "sync_log"
80 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
81 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
82 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
83 #define KEY_DEFAULT_STYLE "default_style"
84 #define KEY_OUNREGISTER_INACTIVE "ounregister_inactive"
85 #define KEY_OUNREGISTER_FLAGS "ounregister_flags"
88 #define KEY_PASSWD "passwd"
89 #define KEY_NICKS "nicks"
90 #define KEY_MASKS "masks"
91 #define KEY_IGNORES "ignores"
92 #define KEY_OPSERV_LEVEL "opserv_level"
93 #define KEY_FLAGS "flags"
94 #define KEY_REGISTER_ON "register"
95 #define KEY_LAST_SEEN "lastseen"
96 #define KEY_INFO "info"
97 #define KEY_USERLIST_STYLE "user_style"
98 #define KEY_SCREEN_WIDTH "screen_width"
99 #define KEY_LAST_AUTHED_HOST "last_authed_host"
100 #define KEY_LAST_QUIT_HOST "last_quit_host"
101 #define KEY_EMAIL_ADDR "email_addr"
102 #define KEY_COOKIE "cookie"
103 #define KEY_COOKIE_DATA "data"
104 #define KEY_COOKIE_TYPE "type"
105 #define KEY_COOKIE_EXPIRES "expires"
106 #define KEY_ACTIVATION "activation"
107 #define KEY_PASSWORD_CHANGE "password change"
108 #define KEY_EMAIL_CHANGE "email change"
109 #define KEY_ALLOWAUTH "allowauth"
110 #define KEY_EPITHET "epithet"
111 #define KEY_TABLE_WIDTH "table_width"
112 #define KEY_ANNOUNCEMENTS "announcements"
113 #define KEY_MAXLOGINS "maxlogins"
114 #define KEY_FAKEHOST "fakehost"
115 #define KEY_NOTE_NOTE "note"
116 #define KEY_NOTE_SETTER "setter"
117 #define KEY_NOTE_DATE "date"
118 #define KEY_KARMA "karma"
119 #define KEY_FORCE_HANDLES_LOWERCASE "force_handles_lowercase"
121 #define KEY_LDAP_ENABLE "ldap_enable"
124 #define KEY_LDAP_URI "ldap_uri"
125 #define KEY_LDAP_BASE "ldap_base"
126 #define KEY_LDAP_DN_FMT "ldap_dn_fmt"
127 #define KEY_LDAP_VERSION "ldap_version"
128 #define KEY_LDAP_AUTOCREATE "ldap_autocreate"
129 #define KEY_LDAP_ADMIN_DN "ldap_admin_dn"
130 #define KEY_LDAP_ADMIN_PASS "ldap_admin_pass"
131 #define KEY_LDAP_FIELD_ACCOUNT "ldap_field_account"
132 #define KEY_LDAP_FIELD_PASSWORD "ldap_field_password"
133 #define KEY_LDAP_FIELD_EMAIL "ldap_field_email"
134 #define KEY_LDAP_FIELD_OSLEVEL "ldap_field_oslevel"
135 #define KEY_LDAP_OBJECT_CLASSES "ldap_object_classes"
136 #define KEY_LDAP_OPER_GROUP_DN "ldap_oper_group_dn"
137 #define KEY_LDAP_OPER_GROUP_LEVEL "ldap_oper_group_level"
138 #define KEY_LDAP_FIELD_GROUP_MEMBER "ldap_field_group_member"
139 #define KEY_LDAP_TIMEOUT "ldap_timeout"
142 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
144 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
145 #define OPTION_FUNC(NAME) int NAME(UNUSED_ARG(struct svccmd *cmd), struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
146 typedef OPTION_FUNC(option_func_t
);
148 DEFINE_LIST(handle_info_list
, struct handle_info
*)
150 #define NICKSERV_MIN_PARMS(N) do { \
152 reply("MSG_MISSING_PARAMS", argv[0]); \
153 svccmd_send_help_brief(user, nickserv, cmd); \
157 struct userNode
*nickserv
;
158 struct userList curr_helpers
;
159 const char *handle_flags
= HANDLE_FLAGS
;
161 extern struct string_list
*autojoin_channels
;
162 static struct module *nickserv_module
;
163 static struct service
*nickserv_service
;
164 static struct log_type
*NS_LOG
;
165 dict_t nickserv_handle_dict
; /* contains struct handle_info* */
166 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
167 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
168 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
169 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
170 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
171 static char handle_inverse_flags
[256];
172 static unsigned int flag_access_levels
[32];
173 static const struct message_entry msgtab
[] = {
174 { "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." },
175 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
176 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu characters or less."},
177 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
178 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
179 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
180 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
181 { "NSMSG_LDAP_FAIL", "There was a problem in contacting the account server (ldap): %s. Please try again later." },
182 { "NSMSG_LDAP_FAIL_ADD", "There was a problem in adding account %s to ldap: %s." },
183 { "NSMSG_LDAP_FAIL_SEND_EMAIL", "There was a problem in storing your email address in the account server (ldap): %s. Please try again later." },
184 { "NSMSG_LDAP_FAIL_GET_EMAIL", "There was a problem in retrieving your email address from the account server (ldap): %s. Please try again later." },
185 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
186 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
187 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
188 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
189 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
190 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
191 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
192 { "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." },
193 { "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." },
194 { "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." },
195 { "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." },
196 { "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." },
197 { "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." },
198 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
199 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
200 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
201 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
202 { "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." },
203 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
204 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
205 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
206 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
207 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
208 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
209 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
210 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
211 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
212 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
213 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
214 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
215 { "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 *@*)." },
216 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
217 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
218 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
219 { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%1$s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %1$s)" },
220 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
221 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
222 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
223 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
224 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
225 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
226 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
227 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
228 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
229 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
230 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
231 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
232 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
233 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
234 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
235 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
236 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
237 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
238 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
239 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
240 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
241 { "NSMSG_HANDLEINFO_KARMA", " Karma: %d" },
242 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
243 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
244 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
245 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
246 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
247 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
248 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
249 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
250 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
251 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
252 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
253 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
254 { "NSMSG_INVALID_KARMA", "$b%s$b is not a valid karma modifier." },
255 { "NSMSG_SET_KARMA", "$bKARMA: $b%d$b" },
256 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
257 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
258 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
259 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
260 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
261 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
262 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
263 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
264 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
265 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
266 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
267 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
268 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
269 { "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)." },
270 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
271 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
272 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
273 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
274 { "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." },
275 { "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." },
276 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
277 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
278 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
279 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
280 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
281 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
282 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
283 { "NSMSG_PASS_SUCCESS", "Password changed." },
284 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
285 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
286 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
287 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
288 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
289 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
290 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
291 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
292 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
293 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
294 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
295 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
296 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
297 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
298 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
299 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
300 { "NSMSG_UNREGISTER_MUST_FORCE", "Account $b%s$b is not inactive or has special flags set; use FORCE to unregister it." },
301 { "NSMSG_UNREGISTER_CANNOT_FORCE", "Account $b%s$b is not inactive or has special flags set; have an IRCOp use FORCE to unregister it." },
302 { "NSMSG_UNREGISTER_NODELETE", "Account $b%s$b is protected from unregistration." },
303 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
304 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
305 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
306 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
307 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
308 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
309 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
310 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
311 { "NSMSG_NO_ACCESS", "Access denied." },
312 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
313 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
314 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
315 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
316 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
317 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
318 { "NSMSG_BAD_HANDLE", "Account $b%s$b is not allowed because it is reserved, is too long, or contains invalid characters." },
319 { "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." },
320 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
321 { "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." },
322 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
323 { "NSMSG_SEARCH_MATCH", "Match: %s" },
324 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
325 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
326 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
327 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
328 { "NSMSG_RECLAIM_HOWTO", "To auth to account %s you must use /msg %s@%s AUTH %s <password>" },
329 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
330 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
331 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
332 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
333 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
334 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
335 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
336 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
337 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
338 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
339 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
340 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
341 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
342 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
343 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
344 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
345 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
346 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
347 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
348 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
349 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
350 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
351 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
352 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
353 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
354 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
355 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
356 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
357 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
358 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
360 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
361 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
363 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
364 { "NSEMAIL_ACTIVATION_BODY",
365 "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"
367 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
368 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
369 "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"
370 "/msg %3$s@%4$s AUTH %5$s your-password\n"
371 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
372 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
374 "If you did NOT request this account, you do not need to do anything.\n"
375 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
376 { "NSEMAIL_ACTIVATION_BODY_WEB",
377 "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"
379 "To verify your email address and complete the account registration, visit the following URL:\n"
380 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
382 "If you did NOT request this account, you do not need to do anything.\n"
383 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
384 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
385 { "NSEMAIL_PASSWORD_CHANGE_BODY",
386 "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"
387 "To complete the password change, log on to %1$s and type the following command:\n"
388 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
389 "If you did NOT request your password to be changed, you do not need to do anything.\n"
390 "Please contact the %1$s staff if you have questions." },
391 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
392 "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"
393 "To complete the password change, click the following URL:\n"
394 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
395 "If you did NOT request your password to be changed, you do not need to do anything.\n"
396 "Please contact the %1$s staff if you have questions." },
397 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
398 #ifdef stupid_verify_old_email
399 { "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." },
400 { "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." },
402 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
403 { "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." },
404 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
405 { "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." },
406 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
407 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
408 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
409 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
410 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
411 { "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." },
412 { "CHECKPASS_YES", "Yes." },
413 { "CHECKPASS_NO", "No." },
414 { "CHECKEMAIL_NOT_SET", "No email set." },
415 { "CHECKEMAIL_YES", "Yes." },
416 { "CHECKEMAIL_NO", "No." },
417 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
421 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
422 static void nickserv_reclaim_p(void *data
);
423 static int nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
);
425 struct nickserv_config nickserv_conf
;
427 /* We have 2^32 unique account IDs to use. */
428 unsigned long int highest_id
= 0;
431 canonicalize_hostmask(char *mask
)
433 char *out
= mask
, *temp
;
434 if ((temp
= strchr(mask
, '!'))) {
436 while (*temp
) *out
++ = *temp
++;
442 static struct handle_note
*
443 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
445 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
447 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
449 memcpy(note
->note
, text
, strlen(text
));
453 static struct handle_info
*
454 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
456 struct handle_info
*hi
;
458 hi
= calloc(1, sizeof(*hi
));
459 hi
->userlist_style
= nickserv_conf
.default_style
? nickserv_conf
.default_style
: HI_DEFAULT_STYLE
;
460 hi
->announcements
= '?';
461 hi
->handle
= strdup(handle
);
462 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
464 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
470 register_nick(const char *nick
, struct handle_info
*owner
)
472 struct nick_info
*ni
;
473 ni
= malloc(sizeof(struct nick_info
));
474 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
476 ni
->next
= owner
->nicks
;
478 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
482 delete_nick(struct nick_info
*ni
)
484 struct nick_info
*last
, *next
;
485 struct userNode
*user
;
486 /* Check to see if we should mark a user as unregistered. */
487 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
488 user
->modes
&= ~FLAGS_REGNICK
;
491 /* Remove ni from the nick_info linked list. */
492 if (ni
== ni
->owner
->nicks
) {
493 ni
->owner
->nicks
= ni
->next
;
495 last
= ni
->owner
->nicks
;
501 last
->next
= next
->next
;
503 dict_remove(nickserv_nick_dict
, ni
->nick
);
506 static unreg_func_t
*unreg_func_list
;
507 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
510 reg_unreg_func(unreg_func_t func
)
512 if (unreg_func_used
== unreg_func_size
) {
513 if (unreg_func_size
) {
514 unreg_func_size
<<= 1;
515 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
518 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
521 unreg_func_list
[unreg_func_used
++] = func
;
525 nickserv_free_cookie(void *data
)
527 struct handle_cookie
*cookie
= data
;
528 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
529 if (cookie
->data
) free(cookie
->data
);
534 free_handle_info(void *vhi
)
536 struct handle_info
*hi
= vhi
;
538 free_string_list(hi
->masks
);
539 free_string_list(hi
->ignores
);
543 delete_nick(hi
->nicks
);
549 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
550 nickserv_free_cookie(hi
->cookie
);
552 if (hi
->email_addr
) {
553 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
554 handle_info_list_remove(hil
, hi
);
556 dict_remove(nickserv_email_dict
, hi
->email_addr
);
561 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
564 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
567 struct userNode
*uNode
;
570 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
572 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
573 if( (rc
= ldap_delete_account(hi
->handle
)) != LDAP_SUCCESS
) {
575 send_message(notify
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
577 if(rc
!= LDAP_NO_SUCH_OBJECT
)
578 return false; /* if theres noone there to delete, its kinda ok, right ?:) */
583 for (n
=0; n
<unreg_func_used
; n
++)
584 unreg_func_list
[n
](notify
, hi
);
586 if (nickserv_conf
.sync_log
) {
587 uNode
= GetUserH(hi
->users
->nick
);
591 set_user_handle_info(hi
->users
, NULL
, 0);
594 if (nickserv_conf
.disable_nicks
)
595 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
597 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
600 if (nickserv_conf
.sync_log
)
601 SyncLog("UNREGISTER %s", hi
->handle
);
603 dict_remove(nickserv_handle_dict
, hi
->handle
);
608 get_handle_info(const char *handle
)
610 return dict_find(nickserv_handle_dict
, handle
, 0);
614 get_nick_info(const char *nick
)
616 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
620 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
625 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
626 mn
= channel
->members
.list
[nn
];
627 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
634 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
635 if (!user
->handle_info
) {
637 send_message(user
, bot
, "MSG_AUTHENTICATE");
641 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
643 send_message(user
, bot
, "NSMSG_NO_ACCESS");
647 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
649 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
653 if (user
->handle_info
->opserv_level
< min_level
) {
655 send_message(user
, bot
, "NSMSG_NO_ACCESS");
663 is_valid_handle(const char *handle
)
665 struct userNode
*user
;
666 /* cant register a juped nick/service nick as handle, to prevent confusion */
667 user
= GetUserH(handle
);
668 if (user
&& IsLocal(user
))
670 /* check against maximum length */
671 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
673 /* for consistency, only allow account names that could be nicks */
674 if (!is_valid_nick(handle
))
676 /* disallow account names that look like bad words */
677 if (opserv_bad_channel(handle
))
679 /* test either regex or containing all valid chars */
680 if (nickserv_conf
.valid_handle_regex_set
) {
681 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
684 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
685 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
689 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
694 is_registerable_nick(const char *nick
)
696 struct userNode
*user
;
697 /* cant register a juped nick/service nick as nick, to prevent confusion */
698 user
= GetUserH(nick
);
699 if (user
&& IsLocal(user
))
701 /* for consistency, only allow nicks names that could be nicks */
702 if (!is_valid_nick(nick
))
704 /* disallow nicks that look like bad words */
705 if (opserv_bad_channel(nick
))
708 if (strlen(nick
) > NICKLEN
)
710 /* test either regex or as valid handle */
711 if (nickserv_conf
.valid_nick_regex_set
) {
712 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
715 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
716 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
722 /* this has been replaced with one in tools.c
725 is_valid_email_addr(const char *email)
727 return strchr(email, '@') != NULL;
733 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
735 if (hi
->email_addr
) {
736 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
737 return hi
->email_addr
;
747 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
749 struct handle_info
*hi
;
750 struct userNode
*target
;
754 if (!(hi
= get_handle_info(++name
))) {
755 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
760 if (!(target
= GetUserH(name
))) {
761 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
764 if (IsLocal(target
)) {
765 if (IsService(target
))
766 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
768 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
771 if (!(hi
= target
->handle_info
)) {
772 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
780 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
781 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
783 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
784 if ((user
->handle_info
->opserv_level
== 1000)
785 || (user
->handle_info
== hi
)
786 || ((user
->handle_info
->opserv_level
== 0)
787 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
788 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
792 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
797 get_victim_oper(struct userNode
*user
, const char *target
)
799 struct handle_info
*hi
;
800 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
802 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
803 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
806 return oper_outranks(user
, hi
) ? hi
: NULL
;
810 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
814 /* If no hostmasks on the account, allow it. */
815 if (!hi
->masks
->used
)
817 /* If any hostmask matches, allow it. */
818 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
819 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0, 0))
821 /* If they are allowauthed to this account, allow it (removing the aa). */
822 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
823 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
826 /* The user is not allowed to use this account. */
831 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
834 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
838 if (len
< nickserv_conf
.password_min_length
) {
840 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
843 if (!irccasecmp(pass
, handle
)) {
845 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
848 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
851 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
854 for (i
=0; i
<len
; i
++) {
855 if (isdigit(pass
[i
]))
857 if (isupper(pass
[i
]))
859 if (islower(pass
[i
]))
862 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
863 || (cnt_upper
< nickserv_conf
.password_min_upper
)
864 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
866 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
872 static auth_func_t
*auth_func_list
;
873 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
876 reg_auth_func(auth_func_t func
)
878 if (auth_func_used
== auth_func_size
) {
879 if (auth_func_size
) {
880 auth_func_size
<<= 1;
881 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
884 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
887 auth_func_list
[auth_func_used
++] = func
;
890 static handle_rename_func_t
*rf_list
;
891 static void **rf_list_extra
;
892 static unsigned int rf_list_size
, rf_list_used
;
895 reg_handle_rename_func(handle_rename_func_t func
, void *extra
)
897 if (rf_list_used
== rf_list_size
) {
900 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
901 rf_list_extra
= realloc(rf_list_extra
, rf_list_size
*sizeof(void*));
904 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
905 rf_list_extra
= malloc(rf_list_size
*sizeof(void*));
908 rf_list
[rf_list_used
] = func
;
909 rf_list_extra
[rf_list_used
++] = extra
;
913 generate_fakehost(struct handle_info
*handle
)
915 struct userNode
*target
;
916 extern const char *hidden_host_suffix
;
917 static char buffer
[HOSTLEN
+1];
921 if (!handle
->fakehost
) {
922 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
927 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
928 else if (style
== 2) {
929 /* Due to the way fakehost is coded theres no way i can
930 get the exact user, so for now ill just take the first
932 for (target
= handle
->users
; target
; target
= target
->next_authed
)
935 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
938 } else if (handle
->fakehost
[0] == '.') {
939 /* A leading dot indicates the stored value is actually a title. */
940 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
943 return handle
->fakehost
;
947 apply_fakehost(struct handle_info
*handle
)
949 struct userNode
*target
;
954 fake
= generate_fakehost(handle
);
955 for (target
= handle
->users
; target
; target
= target
->next_authed
)
956 assign_fakehost(target
, fake
, 1);
959 void send_func_list(struct userNode
*user
)
962 struct handle_info
*old_info
;
964 old_info
= user
->handle_info
;
966 for (n
=0; n
<auth_func_used
; n
++)
967 auth_func_list
[n
](user
, old_info
);
971 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
974 struct handle_info
*old_info
;
976 /* This can happen if somebody uses COOKIE while authed, or if
977 * they re-auth to their current handle (which is silly, but users
979 if (user
->handle_info
== hi
)
982 if (user
->handle_info
) {
983 struct userNode
*other
;
986 userList_remove(&curr_helpers
, user
);
988 /* remove from next_authed linked list */
989 if (user
->handle_info
->users
== user
) {
990 user
->handle_info
->users
= user
->next_authed
;
991 } else if (user
->handle_info
->users
!= NULL
) {
992 for (other
= user
->handle_info
->users
;
993 other
->next_authed
!= user
;
994 other
= other
->next_authed
) ;
995 other
->next_authed
= user
->next_authed
;
997 /* No users authed to the account - can happen if they get
998 * killed for authing. */
1000 /* if nobody left on old handle, and they're not an oper, remove !god */
1001 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
1002 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
1003 /* record them as being last seen at this time */
1004 user
->handle_info
->lastseen
= now
;
1005 /* and record their hostmask */
1006 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
1008 old_info
= user
->handle_info
;
1009 user
->handle_info
= hi
;
1010 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1011 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1013 /* Call auth handlers */
1014 if (!GetUserH(user
->nick
))
1018 struct nick_info
*ni
;
1020 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1021 if (nickserv_conf
.warn_clone_auth
) {
1022 struct userNode
*other
;
1023 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1024 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1027 /* Add this auth to users list of current auths */
1028 user
->next_authed
= hi
->users
;
1031 /* Add to helpers list */
1032 if (IsHelper(user
) && !userList_contains(&curr_helpers
, user
))
1033 userList_append(&curr_helpers
, user
);
1035 /* Set the fakehost */
1036 if (hi
->fakehost
|| old_info
)
1040 #ifdef WITH_PROTOCOL_P10
1041 /* Stamp users with their account name. */
1042 char *id
= hi
->handle
;
1044 const char *id
= "???";
1046 /* Mark all the nicks registered to this
1047 * account as registered nicks
1048 * - Why not just this one? -rubin */
1049 if (!nickserv_conf
.disable_nicks
) {
1050 struct nick_info
*ni2
;
1051 for (ni2
= hi
->nicks
; ni2
; ni2
= ni2
->next
) {
1052 if (!irccasecmp(user
->nick
, ni2
->nick
)) {
1053 user
->modes
|= FLAGS_REGNICK
;
1058 /* send the account to the ircd */
1059 StampUser(user
, id
, hi
->registered
);
1062 /* Stop trying to kick this user off their nick */
1063 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1064 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1066 /* We cannot clear the user's account ID, unfortunately. */
1067 user
->next_authed
= NULL
;
1070 /* Call auth handlers */
1071 if (GetUserH(user
->nick
)) {
1072 for (n
=0; n
<auth_func_used
; n
++) {
1073 auth_func_list
[n
](user
, old_info
);
1080 static struct handle_info
*
1081 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1083 struct handle_info
*hi
;
1084 struct nick_info
*ni
;
1085 char crypted
[MD5_CRYPT_LENGTH
];
1087 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1089 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1093 if(strlen(handle
) > 30)
1096 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 30);
1100 if (!is_secure_password(handle
, passwd
, user
))
1103 cryptpass(passwd
, crypted
);
1105 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1107 rc
= ldap_do_add(handle
, crypted
, NULL
);
1108 if(LDAP_SUCCESS
!= rc
&& LDAP_ALREADY_EXISTS
!= rc
) {
1110 send_message(user
, nickserv
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1115 hi
= register_handle(handle
, crypted
, 0);
1116 hi
->masks
= alloc_string_list(1);
1117 hi
->ignores
= alloc_string_list(1);
1119 hi
->language
= lang_C
;
1120 hi
->registered
= now
;
1122 hi
->flags
= HI_DEFAULT_FLAGS
;
1123 if (settee
&& !no_auth
)
1124 set_user_handle_info(settee
, hi
, 1);
1126 if (user
!= settee
) {
1128 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1130 else if (nickserv_conf
.disable_nicks
) {
1132 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1135 else if (user
&& (ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
))) {
1137 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1142 if (is_registerable_nick(user
->nick
)) {
1143 register_nick(user
->nick
, hi
);
1144 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1148 if (settee
&& (user
!= settee
)) {
1150 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1157 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1159 cookie
->hi
->cookie
= cookie
;
1160 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1163 /* Contributed by the great sneep of afternet ;) */
1164 /* Since this gets used in a URL, we want to avoid stuff that confuses
1165 * email clients such as ] and ?. a-z, 0-9 only.
1167 void genpass(char *str
, int len
)
1172 for(i
= 0; i
< len
; i
++)
1176 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1177 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1185 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1187 struct handle_cookie
*cookie
;
1188 char subject
[128], body
[4096], *misc
;
1189 const char *netname
, *fmt
;
1193 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1197 cookie
= calloc(1, sizeof(*cookie
));
1199 cookie
->type
= type
;
1200 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1202 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1203 /* Adding dedicated password gen function for more control -Rubin */
1204 genpass(cookie
->cookie
, 10);
1206 *inttobase64(cookie->cookie, rand(), 5);
1207 *inttobase64(cookie->cookie+5, rand(), 5);
1210 netname
= nickserv_conf
.network_name
;
1213 switch (cookie
->type
) {
1215 hi
->passwd
[0] = 0; /* invalidate password */
1216 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1217 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1218 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1221 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1223 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1225 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1228 case PASSWORD_CHANGE
:
1229 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1230 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1231 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1233 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1235 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1236 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1240 misc
= hi
->email_addr
;
1241 hi
->email_addr
= cookie
->data
;
1242 #ifdef stupid_verify_old_email
1244 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1245 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1246 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1247 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1248 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1249 mail_send(nickserv
, hi
, subject
, body
, 1);
1250 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1251 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1255 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1256 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1257 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1258 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1259 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1260 mail_send(nickserv
, hi
, subject
, body
, 1);
1262 #ifdef stupid_verify_old_email
1265 hi
->email_addr
= misc
;
1268 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1269 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1270 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1271 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1272 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1275 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1279 mail_send(nickserv
, hi
, subject
, body
, first_time
);
1280 nickserv_bake_cookie(cookie
);
1284 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1286 cookie
->hi
->cookie
= NULL
;
1287 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1288 nickserv_free_cookie(cookie
);
1292 nickserv_free_email_addr(void *data
)
1294 handle_info_list_clean(data
);
1299 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1301 struct handle_info_list
*hil
;
1302 /* Remove from old handle_info_list ... */
1303 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1304 handle_info_list_remove(hil
, hi
);
1305 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1306 hi
->email_addr
= NULL
;
1308 /* Add to the new list.. */
1309 if (new_email_addr
) {
1310 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1311 hil
= calloc(1, sizeof(*hil
));
1312 hil
->tag
= strdup(new_email_addr
);
1313 handle_info_list_init(hil
);
1314 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1316 handle_info_list_append(hil
, hi
);
1317 hi
->email_addr
= hil
->tag
;
1321 static NICKSERV_FUNC(cmd_register
)
1324 struct handle_info
*hi
;
1325 const char *email_addr
, *password
;
1326 char syncpass
[MD5_CRYPT_LENGTH
];
1327 int no_auth
, weblink
;
1329 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1330 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1334 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1335 /* Require the first handle registered to belong to someone +o. */
1336 reply("NSMSG_REQUIRE_OPER");
1340 if (user
->handle_info
) {
1341 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1345 if (IsRegistering(user
)) {
1346 reply("NSMSG_ALREADY_REGISTERING");
1350 if (IsStamped(user
)) {
1351 /* Unauthenticated users might still have been stamped
1352 previously and could therefore have a hidden host;
1353 do not allow them to register a new account. */
1354 reply("NSMSG_STAMPED_REGISTER");
1358 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1360 if(nickserv_conf
.force_handles_lowercase
)
1361 irc_strtolower(argv
[1]);
1362 if (!is_valid_handle(argv
[1])) {
1363 reply("NSMSG_BAD_HANDLE", argv
[1]);
1368 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1369 struct handle_info_list
*hil
;
1372 /* Remember email address. */
1373 email_addr
= argv
[3];
1375 /* Check that the email address looks valid.. */
1376 if (!valid_email(email_addr
)) {
1377 reply("NSMSG_BAD_EMAIL_ADDR");
1381 /* .. and that we are allowed to send to it. */
1382 if ((str
= mail_prohibited_address(email_addr
))) {
1383 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1387 /* If we do email verify, make sure we don't spam the address. */
1388 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1390 for (nn
=0; nn
<hil
->used
; nn
++) {
1391 if (hil
->list
[nn
]->cookie
) {
1392 reply("NSMSG_EMAIL_UNACTIVATED");
1396 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1397 reply("NSMSG_EMAIL_OVERUSED");
1410 /* Webregister hack - send URL instead of IRC cookie
1413 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1417 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1419 /* Add any masks they should get. */
1420 if (nickserv_conf
.default_hostmask
) {
1421 string_list_append(hi
->masks
, strdup("*@*"));
1423 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1424 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1425 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1428 /* If they're the first to register, give them level 1000. */
1429 if (dict_size(nickserv_handle_dict
) == 1) {
1430 hi
->opserv_level
= 1000;
1431 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1434 /* Set their email address. */
1437 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1439 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email_addr
)) != LDAP_SUCCESS
) {
1440 /* Falied to update email in ldap, but still
1441 * updated it here.. what should we do? */
1442 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1444 nickserv_set_email_addr(hi
, email_addr
);
1448 nickserv_set_email_addr(hi
, email_addr
);
1451 nickserv_set_email_addr(hi
, email_addr
);
1455 /* If they need to do email verification, tell them. */
1457 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1459 /* Set registering flag.. */
1460 user
->modes
|= FLAGS_REGISTERING
;
1462 if (nickserv_conf
.sync_log
) {
1463 cryptpass(password
, syncpass
);
1465 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1466 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1469 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1472 /* this wont work if email is required .. */
1473 process_adduser_pending(user
);
1478 static NICKSERV_FUNC(cmd_oregister
)
1480 struct userNode
*settee
= NULL
;
1481 struct handle_info
*hi
;
1482 char* account
= NULL
;
1488 NICKSERV_MIN_PARMS(2);
1492 if(nickserv_conf
.force_handles_lowercase
)
1493 irc_strtolower(account
);
1494 if (!is_valid_handle(argv
[1])) {
1495 reply("NSMSG_BAD_HANDLE", argv
[1]);
1498 if (nickserv_conf
.email_required
) {
1499 NICKSERV_MIN_PARMS(3);
1501 if (argc
> 4) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1502 if (strchr(argv
[4], '@'))
1512 if (argc
> 3) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1513 if (strchr(argv
[3], '@'))
1522 /* If they passed a nick, look for that user.. */
1523 if (nick
&& !(settee
= GetUserH(nick
))) {
1524 reply("MSG_NICK_UNKNOWN", argv
[4]);
1527 /* If the setee is already authed, we cant add a 2nd account for them.. */
1528 if (settee
&& settee
->handle_info
) {
1529 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1532 /* If there is no default mask in the conf, and they didn't pass a mask,
1533 * but we did find a user by nick, generate the mask */
1535 if (nickserv_conf
.default_hostmask
)
1538 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1540 reply("NSMSG_REGISTER_BAD_NICKMASK");
1545 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1546 return 0; /* error reply handled by above */
1550 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1552 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email
)) != LDAP_SUCCESS
) {
1553 /* Falied to update email in ldap, but still
1554 * updated it here.. what should we do? */
1555 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1557 nickserv_set_email_addr(hi
, email
);
1561 nickserv_set_email_addr(hi
, email
);
1564 nickserv_set_email_addr(hi
, email
);
1568 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1569 if (mask_canonicalized
)
1570 string_list_append(hi
->masks
, mask_canonicalized
);
1573 if (nickserv_conf
.sync_log
)
1574 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1579 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1582 struct userNode
*target
;
1583 char *new_mask
= strdup(pretty_mask(mask
));
1584 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1585 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1586 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1591 string_list_append(hi
->ignores
, new_mask
);
1592 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1594 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1595 irc_silence(target
, new_mask
, 1);
1600 static NICKSERV_FUNC(cmd_addignore
)
1602 NICKSERV_MIN_PARMS(2);
1604 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1607 static NICKSERV_FUNC(cmd_oaddignore
)
1609 struct handle_info
*hi
;
1611 NICKSERV_MIN_PARMS(3);
1612 if (!(hi
= get_victim_oper(user
, argv
[1])))
1615 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1619 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1622 struct userNode
*target
;
1623 char *pmask
= strdup(pretty_mask(del_mask
));
1624 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1625 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1626 char *old_mask
= hi
->ignores
->list
[i
];
1627 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1628 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1629 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1630 irc_silence(target
, old_mask
, 0);
1637 reply("NSMSG_DELMASK_NOT_FOUND");
1641 static NICKSERV_FUNC(cmd_delignore
)
1643 NICKSERV_MIN_PARMS(2);
1644 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1647 static NICKSERV_FUNC(cmd_odelignore
)
1649 struct handle_info
*hi
;
1650 NICKSERV_MIN_PARMS(3);
1651 if (!(hi
= get_victim_oper(user
, argv
[1])))
1653 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1656 static NICKSERV_FUNC(cmd_handleinfo
)
1659 unsigned int i
, pos
=0, herelen
;
1660 struct userNode
*target
, *next_un
;
1661 struct handle_info
*hi
;
1662 const char *nsmsg_none
;
1665 if (!(hi
= user
->handle_info
)) {
1666 reply("NSMSG_MUST_AUTH");
1669 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1673 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1674 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1676 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1679 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1680 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1682 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1685 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1686 if (HANDLE_FLAGGED(hi
, FROZEN
))
1687 reply("NSMSG_HANDLEINFO_VACATION");
1689 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1690 struct do_not_register
*dnr
;
1691 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1692 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1693 if ((user
->handle_info
->opserv_level
< 900) && !oper_outranks(user
, hi
))
1695 } else if (hi
!= user
->handle_info
) {
1696 reply("NSMSG_HANDLEINFO_END");
1701 reply("NSMSG_HANDLEINFO_KARMA", hi
->karma
);
1703 if (nickserv_conf
.email_enabled
)
1704 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1708 switch (hi
->cookie
->type
) {
1709 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1710 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1711 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1712 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1713 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1719 unsigned long flen
= 1;
1720 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1722 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1723 if (hi
->flags
& 1 << i
)
1724 flags
[flen
++] = handle_flags
[i
];
1726 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1728 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1731 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1732 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1733 || (hi
->opserv_level
> 0)) {
1734 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1737 if (IsHelping(user
) || IsOper(user
))
1742 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1743 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1748 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1750 if (hi
->last_quit_host
[0])
1751 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1753 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1755 if (nickserv_conf
.disable_nicks
) {
1756 /* nicks disabled; don't show anything about registered nicks */
1757 } else if (hi
->nicks
) {
1758 struct nick_info
*ni
, *next_ni
;
1759 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1760 herelen
= strlen(ni
->nick
);
1761 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1763 goto print_nicks_buff
;
1767 memcpy(buff
+pos
, ni
->nick
, herelen
);
1768 pos
+= herelen
; buff
[pos
++] = ' ';
1772 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1777 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1780 if (hi
->masks
->used
) {
1781 for (i
=0; i
< hi
->masks
->used
; i
++) {
1782 herelen
= strlen(hi
->masks
->list
[i
]);
1783 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1785 goto print_mask_buff
;
1787 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1788 pos
+= herelen
; buff
[pos
++] = ' ';
1789 if (i
+1 == hi
->masks
->used
) {
1792 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1797 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1800 if (hi
->ignores
->used
) {
1801 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1802 herelen
= strlen(hi
->ignores
->list
[i
]);
1803 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1805 goto print_ignore_buff
;
1807 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1808 pos
+= herelen
; buff
[pos
++] = ' ';
1809 if (i
+1 == hi
->ignores
->used
) {
1812 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1817 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1821 struct userData
*chan
, *next
;
1824 for (chan
= hi
->channels
; chan
; chan
= next
) {
1825 next
= chan
->u_next
;
1826 name
= chan
->channel
->channel
->name
;
1827 herelen
= strlen(name
);
1828 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1830 goto print_chans_buff
;
1832 if (IsUserSuspended(chan
))
1834 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(chan
->access
), name
);
1838 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1843 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1846 for (target
= hi
->users
; target
; target
= next_un
) {
1847 herelen
= strlen(target
->nick
);
1848 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1850 goto print_cnick_buff
;
1852 next_un
= target
->next_authed
;
1854 memcpy(buff
+pos
, target
->nick
, herelen
);
1855 pos
+= herelen
; buff
[pos
++] = ' ';
1859 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1864 reply("NSMSG_HANDLEINFO_END");
1865 return 1 | ((hi
!= user
->handle_info
) ? CMD_LOG_STAFF
: 0);
1868 static NICKSERV_FUNC(cmd_userinfo
)
1870 struct userNode
*target
;
1872 NICKSERV_MIN_PARMS(2);
1873 if (!(target
= GetUserH(argv
[1]))) {
1874 reply("MSG_NICK_UNKNOWN", argv
[1]);
1877 if (target
->handle_info
)
1878 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1880 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1884 static NICKSERV_FUNC(cmd_nickinfo
)
1886 struct nick_info
*ni
;
1888 NICKSERV_MIN_PARMS(2);
1889 if (!(ni
= get_nick_info(argv
[1]))) {
1890 reply("MSG_NICK_UNKNOWN", argv
[1]);
1893 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1897 static NICKSERV_FUNC(cmd_rename_handle
)
1899 struct handle_info
*hi
;
1900 struct userNode
*uNode
;
1904 NICKSERV_MIN_PARMS(3);
1905 if(nickserv_conf
.force_handles_lowercase
)
1906 irc_strtolower(argv
[2]);
1907 if (!(hi
= get_victim_oper(user
, argv
[1])))
1909 if (!is_valid_handle(argv
[2])) {
1910 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1913 if (get_handle_info(argv
[2])) {
1914 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1917 if(strlen(argv
[2]) > 30)
1919 reply("NMSG_HANDLE_TOLONG", argv
[2], 30);
1923 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1925 if( (rc
= ldap_rename_account(hi
->handle
, argv
[2])) != LDAP_SUCCESS
) {
1926 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1932 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1933 hi
->handle
= strdup(argv
[2]);
1934 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1935 for (nn
=0; nn
<rf_list_used
; nn
++)
1936 rf_list
[nn
](hi
, old_handle
, rf_list_extra
[nn
]);
1938 if (nickserv_conf
.sync_log
) {
1939 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1940 irc_rename(uNode
, hi
->handle
);
1942 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1945 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1946 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1947 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1953 static failpw_func_t
*failpw_func_list
;
1954 static void **failpw_func_list_extra
;
1955 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1958 reg_failpw_func(failpw_func_t func
, void *extra
)
1960 if (failpw_func_used
== failpw_func_size
) {
1961 if (failpw_func_size
) {
1962 failpw_func_size
<<= 1;
1963 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1964 failpw_func_list_extra
= realloc(failpw_func_list_extra
, failpw_func_size
*sizeof(void*));
1966 failpw_func_size
= 8;
1967 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1968 failpw_func_list_extra
= malloc(failpw_func_size
*sizeof(void*));
1971 failpw_func_list
[failpw_func_used
] = func
;
1972 failpw_func_list_extra
[failpw_func_used
++] = extra
;
1976 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1978 * called by nefariouses enhanced AC login-on-connect code
1981 struct handle_info
*loc_auth(char *handle
, char *password
, char *userhost
)
1983 int pw_arg
, used
, maxlogins
;
1986 struct handle_info
*hi
;
1987 struct userNode
*other
;
1989 int ldap_result
= LDAP_SUCCESS
;
1993 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1997 if(nickserv_conf
.ldap_enable
) {
1998 ldap_result
= ldap_check_auth(handle
, password
);
1999 if(ldap_result
!= LDAP_SUCCESS
) {
2008 if (!checkpass(password
, hi
->passwd
)) {
2013 /* ldap libs are present but we are not using them... */
2014 if( !nickserv_conf
.ldap_enable
) {
2018 if (!checkpass(password
, hi
->passwd
)) {
2022 else if( (!hi
) && ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2023 /* user not found, but authed to ldap successfully..
2024 * create the account.
2029 /* Add a *@* mask */
2030 /* TODO if userhost is not null, build mask based on that. */
2031 if(nickserv_conf
.default_hostmask
)
2034 return NULL
; /* They dont have a *@* mask so they can't loc */
2036 if(!(hi
= nickserv_register(NULL
, NULL
, handle
, password
, 0))) {
2037 return 0; /* couldn't add the user for some reason */
2040 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2042 if(nickserv_conf
.email_required
) {
2047 nickserv_set_email_addr(hi
, email
);
2051 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2052 string_list_append(hi
->masks
, mask_canonicalized
);
2054 if(nickserv_conf
.sync_log
)
2055 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, "@", handle
);
2059 /* Still no account, so just fail out */
2064 /* We don't know the users hostname, or anything because they
2065 * havn't registered yet. So we can only allow LOC if your
2066 * account has *@* as a hostmask.
2068 * UPDATE: New nefarious LOC supports u@h
2078 buf
= strdup(userhost
);
2079 ident
= mysep(&buf
, "@");
2080 realhost
= mysep(&buf
, ":");
2081 ip
= mysep(&buf
, ":");
2082 if(!ip
|| !realhost
|| !ident
) {
2084 return NULL
; /* Invalid AC request, just quit */
2086 uh
= malloc(strlen(userhost
));
2087 ui
= malloc(strlen(userhost
));
2088 sprintf(uh
, "%s@%s", ident
, realhost
);
2089 sprintf(ui
, "%s@%s", ident
, ip
);
2090 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2092 if(match_ircglob(uh
, hi
->masks
->list
[ii
])
2093 || match_ircglob(ui
, hi
->masks
->list
[ii
]))
2105 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2107 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
2117 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2121 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2122 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2123 if (++used
>= maxlogins
) {
2127 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2131 static NICKSERV_FUNC(cmd_auth
)
2133 char *privv
[MAXNUMPARAMS
];
2135 int pw_arg
, used
, maxlogins
;
2136 struct handle_info
*hi
;
2139 struct userNode
*other
;
2141 int ldap_result
= LDAP_OTHER
;
2145 if (user
->handle_info
) {
2146 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2149 if (IsStamped(user
)) {
2150 /* Unauthenticated users might still have been stamped
2151 previously and could therefore have a hidden host;
2152 do not allow them to authenticate. */
2153 reply("NSMSG_STAMPED_AUTH");
2160 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
2161 } else if (argc
== 2) {
2164 if (nickserv_conf
.disable_nicks
) {
2165 hi
= get_handle_info(user
->nick
);
2167 /* try to look up their handle from their nick */
2168 /* TODO: handle ldap auth on nickserv style networks, too */
2169 struct nick_info
*ni
;
2170 ni
= get_nick_info(user
->nick
);
2172 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
2178 handle
= hi
->handle
;
2180 handle
= user
->nick
;
2183 reply("MSG_MISSING_PARAMS", argv
[0]);
2184 svccmd_send_help_brief(user
, nickserv
, cmd
);
2189 if(strchr(argv
[1], '<') || strchr(handle
, '>')) {
2190 reply("NSMSG_NO_ANGLEBRACKETS");
2193 if (!is_valid_handle(handle
)) {
2194 reply("NSMSG_BAD_HANDLE", handle
);
2198 if(nickserv_conf
.ldap_enable
) {
2199 ldap_result
= ldap_check_auth(handle
, passwd
);
2200 /* Get the users email address and update it */
2201 if(ldap_result
== LDAP_SUCCESS
) {
2203 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2205 if(nickserv_conf
.email_required
) {
2206 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc
));
2211 else if(ldap_result
!= LDAP_INVALID_CREDENTIALS
) {
2212 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2220 if(nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2221 /* user not found, but authed to ldap successfully..
2222 * create the account.
2225 if(!(hi
= nickserv_register(user
, NULL
, argv
[1], argv
[2], 0))) {
2226 reply("NSMSG_UNABLE_TO_ADD");
2227 return 0; /* couldn't add the user for some reason */
2229 /* Add a *@* mask */
2230 if(nickserv_conf
.default_hostmask
)
2233 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2236 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2237 string_list_append(hi
->masks
, mask_canonicalized
);
2240 nickserv_set_email_addr(hi
, email
);
2243 if(nickserv_conf
.sync_log
)
2244 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
);
2248 reply("NSMSG_HANDLE_NOT_FOUND");
2254 /* Responses from here on look up the language used by the handle they asked about. */
2255 if (!valid_user_for(user
, hi
)) {
2256 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
2257 send_message_type(4, user
, cmd
->parent
->bot
,
2258 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
2261 send_message_type(4, user
, cmd
->parent
->bot
,
2262 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
2264 argv
[pw_arg
] = "BADMASK";
2268 if( ( nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_INVALID_CREDENTIALS
) ||
2269 ( (!nickserv_conf
.ldap_enable
) && (!checkpass(passwd
, hi
->passwd
)) ) ) {
2271 if (!checkpass(passwd
, hi
->passwd
)) {
2274 send_message_type(4, user
, cmd
->parent
->bot
,
2275 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
2276 argv
[pw_arg
] = "BADPASS";
2277 for (n
=0; n
<failpw_func_used
; n
++)
2278 failpw_func_list
[n
](user
, hi
, failpw_func_list_extra
[n
]);
2279 if (nickserv_conf
.autogag_enabled
) {
2280 if (!user
->auth_policer
.params
) {
2281 user
->auth_policer
.last_req
= now
;
2282 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
2284 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
2286 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
2287 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
2288 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2290 argv
[pw_arg
] = "GAGGED";
2295 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2296 send_message_type(4, user
, cmd
->parent
->bot
,
2297 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2298 argv
[pw_arg
] = "SUSPENDED";
2301 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2302 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2303 if (++used
>= maxlogins
) {
2304 send_message_type(4, user
, cmd
->parent
->bot
,
2305 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2307 argv
[pw_arg
] = "MAXLOGINS";
2312 set_user_handle_info(user
, hi
, 1);
2313 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2314 reply("NSMSG_PLEASE_SET_EMAIL");
2315 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2316 reply("NSMSG_WEAK_PASSWORD");
2317 if (hi
->passwd
[0] != '$')
2318 cryptpass(passwd
, hi
->passwd
);
2320 /* If a channel was waiting for this user to auth,
2321 * finish adding them */
2322 process_adduser_pending(user
);
2324 reply("NSMSG_AUTH_SUCCESS");
2327 /* Set +x if autohide is on */
2328 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2329 irc_umode(user
, "+x");
2331 if(!IsOper(user
)) /* If they arnt already opered.. */
2333 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2334 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2336 if (nickserv_conf
.auto_admin_privs
[0]) {
2337 irc_raw_privs(user
, nickserv_conf
.auto_admin_privs
);
2338 privc
= split_line(strdup(nickserv_conf
.auto_admin_privs
), false, MAXNUMPARAMS
, privv
);
2339 for (i
= 0; i
< privc
; i
++) {
2340 client_modify_priv_by_name(user
, privv
[i
], 1);
2343 irc_umode(user
,nickserv_conf
.auto_admin
);
2344 reply("NSMSG_AUTO_OPER_ADMIN");
2346 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2348 if (nickserv_conf
.auto_oper_privs
[0]) {
2349 irc_raw_privs(user
, nickserv_conf
.auto_oper_privs
);
2350 privc
= split_line(strdup(nickserv_conf
.auto_oper_privs
), false, MAXNUMPARAMS
, privv
);
2351 for (i
= 0; i
< privc
; i
++) {
2352 client_modify_priv_by_name(user
, privv
[i
], 1);
2355 irc_umode(user
,nickserv_conf
.auto_oper
);
2356 reply("NSMSG_AUTO_OPER");
2360 /* Wipe out the pass for the logs */
2362 if (!hi
->masks
->used
) {
2364 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2365 if (irc_in_addr_is_valid(user
->ip
) && irc_pton(&ip
, NULL
, user
->hostname
))
2366 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2369 argv
[pw_arg
] = "****";
2373 static allowauth_func_t
*allowauth_func_list
;
2374 static void **allowauth_func_list_extra
;
2375 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2378 reg_allowauth_func(allowauth_func_t func
, void *extra
)
2380 if (allowauth_func_used
== allowauth_func_size
) {
2381 if (allowauth_func_size
) {
2382 allowauth_func_size
<<= 1;
2383 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2384 allowauth_func_list_extra
= realloc(allowauth_func_list_extra
, allowauth_func_size
*sizeof(void*));
2386 allowauth_func_size
= 8;
2387 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2388 allowauth_func_list_extra
= malloc(allowauth_func_size
*sizeof(void*));
2391 allowauth_func_list
[allowauth_func_used
] = func
;
2392 allowauth_func_list_extra
[allowauth_func_used
++] = extra
;
2395 static NICKSERV_FUNC(cmd_allowauth
)
2397 struct userNode
*target
;
2398 struct handle_info
*hi
;
2401 NICKSERV_MIN_PARMS(2);
2402 if (!(target
= GetUserH(argv
[1]))) {
2403 reply("MSG_NICK_UNKNOWN", argv
[1]);
2406 if (target
->handle_info
) {
2407 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2410 if (IsStamped(target
)) {
2411 /* Unauthenticated users might still have been stamped
2412 previously and could therefore have a hidden host;
2413 do not allow them to authenticate to an account. */
2414 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2419 else if (!(hi
= get_handle_info(argv
[2]))) {
2420 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2424 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2425 reply("MSG_USER_OUTRANKED", hi
->handle
);
2428 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2429 || (hi
->opserv_level
> 0))
2430 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2431 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2434 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2435 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2436 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2437 if (nickserv_conf
.email_enabled
)
2438 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2440 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2441 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2443 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2445 for (n
=0; n
<allowauth_func_used
; n
++)
2446 allowauth_func_list
[n
](user
, target
, hi
, allowauth_func_list_extra
[n
]);
2450 static NICKSERV_FUNC(cmd_authcookie
)
2452 struct handle_info
*hi
;
2454 NICKSERV_MIN_PARMS(2);
2455 if (user
->handle_info
) {
2456 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2459 if (IsStamped(user
)) {
2460 /* Unauthenticated users might still have been stamped
2461 previously and could therefore have a hidden host;
2462 do not allow them to authenticate to an account. */
2463 reply("NSMSG_STAMPED_AUTHCOOKIE");
2466 if (!(hi
= get_handle_info(argv
[1]))) {
2467 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2470 if (!hi
->email_addr
) {
2471 reply("MSG_SET_EMAIL_ADDR");
2474 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2478 static NICKSERV_FUNC(cmd_delcookie
)
2480 struct handle_info
*hi
;
2482 hi
= user
->handle_info
;
2484 reply("NSMSG_NO_COOKIE");
2487 switch (hi
->cookie
->type
) {
2490 reply("NSMSG_MUST_TIME_OUT");
2493 nickserv_eat_cookie(hi
->cookie
);
2494 reply("NSMSG_ATE_COOKIE");
2500 static NICKSERV_FUNC(cmd_odelcookie
)
2502 struct handle_info
*hi
;
2504 NICKSERV_MIN_PARMS(2);
2506 if (!(hi
= get_victim_oper(user
, argv
[1])))
2510 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2514 switch (hi
->cookie
->type
) {
2516 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2517 if (nickserv_conf
.sync_log
)
2518 SyncLog("ACCOUNTACC %s", hi
->handle
);
2520 case PASSWORD_CHANGE
:
2521 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2522 if (nickserv_conf
.sync_log
)
2523 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2526 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2527 if (nickserv_conf
.sync_log
)
2528 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2531 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2533 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2534 /* Falied to update email in ldap, but still
2535 * updated it here.. what should we do? */
2536 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2538 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2542 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2545 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2547 if (nickserv_conf
.sync_log
)
2548 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2551 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2552 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2556 nickserv_eat_cookie(hi
->cookie
);
2557 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2562 static NICKSERV_FUNC(cmd_resetpass
)
2564 struct handle_info
*hi
;
2565 char crypted
[MD5_CRYPT_LENGTH
];
2568 NICKSERV_MIN_PARMS(3);
2569 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2573 if (user
->handle_info
) {
2574 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2577 if (IsStamped(user
)) {
2578 /* Unauthenticated users might still have been stamped
2579 previously and could therefore have a hidden host;
2580 do not allow them to activate an account. */
2581 reply("NSMSG_STAMPED_RESETPASS");
2584 if (!(hi
= get_handle_info(argv
[1]))) {
2585 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2588 if (!hi
->email_addr
) {
2589 reply("MSG_SET_EMAIL_ADDR");
2592 cryptpass(argv
[2], crypted
);
2594 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2598 static NICKSERV_FUNC(cmd_cookie
)
2600 struct handle_info
*hi
;
2603 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2606 NICKSERV_MIN_PARMS(3);
2607 if (!(hi
= get_handle_info(argv
[1]))) {
2608 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2614 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2615 reply("NSMSG_HANDLE_SUSPENDED");
2620 reply("NSMSG_NO_COOKIE");
2624 /* Check validity of operation before comparing cookie to
2625 * prohibit guessing by authed users. */
2626 if (user
->handle_info
2627 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2628 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2629 reply("NSMSG_CANNOT_COOKIE");
2633 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2634 reply("NSMSG_BAD_COOKIE");
2638 switch (hi
->cookie
->type
) {
2641 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2643 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2644 /* Falied to update email in ldap, but still
2645 * updated it here.. what should we do? */
2646 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2651 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2652 set_user_handle_info(user
, hi
, 1);
2653 reply("NSMSG_HANDLE_ACTIVATED");
2654 if (nickserv_conf
.sync_log
)
2655 SyncLog("ACCOUNTACC %s", hi
->handle
);
2657 case PASSWORD_CHANGE
:
2659 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2661 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2662 /* Falied to update email in ldap, but still
2663 * updated it here.. what should we do? */
2664 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2669 set_user_handle_info(user
, hi
, 1);
2670 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2671 reply("NSMSG_PASSWORD_CHANGED");
2672 if (nickserv_conf
.sync_log
)
2673 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2677 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2679 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2680 /* Falied to update email in ldap, but still
2681 * updated it here.. what should we do? */
2682 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2687 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2689 * This should only happen if an OREGISTER was sent. Require
2690 * email must be enabled! - SiRVulcaN
2692 if (nickserv_conf
.sync_log
)
2693 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2696 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2697 reply("NSMSG_EMAIL_CHANGED");
2698 if (nickserv_conf
.sync_log
)
2699 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2702 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2703 set_user_handle_info(user
, hi
, 1);
2704 nickserv_addmask(user
, hi
, mask
);
2705 reply("NSMSG_AUTH_SUCCESS");
2710 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2711 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2715 nickserv_eat_cookie(hi
->cookie
);
2717 process_adduser_pending(user
);
2722 static NICKSERV_FUNC(cmd_oregnick
) {
2724 struct handle_info
*target
;
2725 struct nick_info
*ni
;
2727 NICKSERV_MIN_PARMS(3);
2728 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2731 if (!is_registerable_nick(nick
)) {
2732 reply("NSMSG_BAD_NICK", nick
);
2735 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2737 reply("NSMSG_NICK_EXISTS", nick
);
2740 register_nick(nick
, target
);
2741 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2745 static NICKSERV_FUNC(cmd_regnick
) {
2747 struct nick_info
*ni
;
2749 if (!is_registerable_nick(user
->nick
)) {
2750 reply("NSMSG_BAD_NICK", user
->nick
);
2753 /* count their nicks, see if it's too many */
2754 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2755 if (n
>= nickserv_conf
.nicks_per_handle
) {
2756 reply("NSMSG_TOO_MANY_NICKS");
2759 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2761 reply("NSMSG_NICK_EXISTS", user
->nick
);
2764 register_nick(user
->nick
, user
->handle_info
);
2765 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2769 static NICKSERV_FUNC(cmd_pass
)
2771 struct handle_info
*hi
;
2772 char *old_pass
, *new_pass
;
2773 char crypted
[MD5_CRYPT_LENGTH
+1];
2778 NICKSERV_MIN_PARMS(3);
2779 hi
= user
->handle_info
;
2783 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2786 if(nickserv_conf
.ldap_enable
) {
2787 ldap_result
= ldap_check_auth(hi
->handle
, old_pass
);
2788 if(ldap_result
!= LDAP_SUCCESS
) {
2789 if(ldap_result
== LDAP_INVALID_CREDENTIALS
)
2790 reply("NSMSG_PASSWORD_INVALID");
2792 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2797 if (!checkpass(old_pass
, hi
->passwd
)) {
2798 argv
[1] = "BADPASS";
2799 reply("NSMSG_PASSWORD_INVALID");
2802 cryptpass(new_pass
, crypted
);
2804 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2806 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
2807 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2812 //cryptpass(new_pass, hi->passwd);
2813 strcpy(hi
->passwd
, crypted
);
2814 if (nickserv_conf
.sync_log
)
2815 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2817 reply("NSMSG_PASS_SUCCESS");
2822 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2825 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2826 for (i
=0; i
<hi
->masks
->used
; i
++) {
2827 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2828 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2833 string_list_append(hi
->masks
, new_mask
);
2834 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2838 static NICKSERV_FUNC(cmd_addmask
)
2841 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2842 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2846 if (!is_gline(argv
[1])) {
2847 reply("NSMSG_MASK_INVALID", argv
[1]);
2850 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2854 static NICKSERV_FUNC(cmd_oaddmask
)
2856 struct handle_info
*hi
;
2858 NICKSERV_MIN_PARMS(3);
2859 if (!(hi
= get_victim_oper(user
, argv
[1])))
2861 return nickserv_addmask(user
, hi
, argv
[2]);
2865 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
, int force
)
2868 for (i
=0; i
<hi
->masks
->used
; i
++) {
2869 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2870 char *old_mask
= hi
->masks
->list
[i
];
2871 if (hi
->masks
->used
== 1 && !force
) {
2872 reply("NSMSG_DELMASK_NOTLAST");
2875 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2876 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2881 reply("NSMSG_DELMASK_NOT_FOUND");
2885 static NICKSERV_FUNC(cmd_delmask
)
2887 NICKSERV_MIN_PARMS(2);
2888 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1], 0);
2891 static NICKSERV_FUNC(cmd_odelmask
)
2893 struct handle_info
*hi
;
2894 NICKSERV_MIN_PARMS(3);
2895 if (!(hi
= get_victim_oper(user
, argv
[1])))
2897 return nickserv_delmask(cmd
, user
, hi
, argv
[2], 1);
2901 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2902 unsigned int nn
, add
= 1, pos
;
2903 unsigned long added
, removed
, flag
;
2905 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2907 case '+': add
= 1; break;
2908 case '-': add
= 0; break;
2910 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2911 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2914 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2915 /* cheesy avoidance of looking up the flag name.. */
2916 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2919 flag
= 1 << (pos
- 1);
2921 added
|= flag
, removed
&= ~flag
;
2923 removed
|= flag
, added
&= ~flag
;
2928 *premoved
= removed
;
2933 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2935 unsigned long before
, after
, added
, removed
;
2936 struct userNode
*uNode
;
2938 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2939 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2941 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2942 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2944 /* Strip helping flag if they're only a support helper and not
2945 * currently in #support. */
2946 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2947 struct channelList
*schannels
;
2949 schannels
= chanserv_support_channels();
2950 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2951 if (find_handle_in_channel(schannels
->list
[ii
], hi
, NULL
))
2953 if (ii
== schannels
->used
)
2954 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2957 if (after
&& !before
) {
2958 /* Add user to current helper list. */
2959 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2960 userList_append(&curr_helpers
, uNode
);
2961 } else if (!after
&& before
) {
2962 /* Remove user from current helper list. */
2963 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2964 userList_remove(&curr_helpers
, uNode
);
2971 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2975 char *set_display
[] = {
2976 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2977 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2978 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2981 reply("NSMSG_SETTING_LIST");
2982 reply("NSMSG_SETTING_LIST_HEADER");
2984 /* Do this so options are presented in a consistent order. */
2985 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2986 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2987 opt(cmd
, user
, hi
, override
, 0, NULL
);
2988 reply("NSMSG_SETTING_LIST_END");
2991 static NICKSERV_FUNC(cmd_set
)
2993 struct handle_info
*hi
;
2996 hi
= user
->handle_info
;
2998 set_list(cmd
, user
, hi
, 0);
3001 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
3002 reply("NSMSG_INVALID_OPTION", argv
[1]);
3005 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
3008 static NICKSERV_FUNC(cmd_oset
)
3010 struct handle_info
*hi
;
3013 NICKSERV_MIN_PARMS(2);
3015 if (!(hi
= get_victim_oper(user
, argv
[1])))
3019 set_list(cmd
, user
, hi
, 0);
3023 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
3024 reply("NSMSG_INVALID_OPTION", argv
[2]);
3028 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
3031 static OPTION_FUNC(opt_info
)
3035 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
3037 hi
->infoline
= NULL
;
3039 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
3043 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
3044 reply("NSMSG_SET_INFO", info
);
3048 static OPTION_FUNC(opt_width
)
3051 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
3053 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
3054 hi
->screen_width
= MIN_LINE_SIZE
;
3055 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3056 hi
->screen_width
= MAX_LINE_SIZE
;
3058 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
3062 static OPTION_FUNC(opt_tablewidth
)
3065 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
3067 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
3068 hi
->table_width
= MIN_LINE_SIZE
;
3069 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3070 hi
->table_width
= MAX_LINE_SIZE
;
3072 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
3076 static OPTION_FUNC(opt_color
)
3079 if (enabled_string(argv
[1]))
3080 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
3081 else if (disabled_string(argv
[1]))
3082 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
3084 reply("MSG_INVALID_BINARY", argv
[1]);
3089 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
3093 static OPTION_FUNC(opt_privmsg
)
3096 if (enabled_string(argv
[1]))
3097 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
3098 else if (disabled_string(argv
[1]))
3099 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
3101 reply("MSG_INVALID_BINARY", argv
[1]);
3106 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
3110 static OPTION_FUNC(opt_autohide
)
3113 if (enabled_string(argv
[1]))
3114 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
3115 else if (disabled_string(argv
[1]))
3116 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
3118 reply("MSG_INVALID_BINARY", argv
[1]);
3123 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
3127 static OPTION_FUNC(opt_style
)
3132 if (!irccasecmp(argv
[1], "Clean"))
3133 hi
->userlist_style
= HI_STYLE_CLEAN
;
3134 else if (!irccasecmp(argv
[1], "Advanced"))
3135 hi
->userlist_style
= HI_STYLE_ADVANCED
;
3136 else if (!irccasecmp(argv
[1], "Classic"))
3137 hi
->userlist_style
= HI_STYLE_CLASSIC
;
3138 else /* Default to normal */
3139 hi
->userlist_style
= HI_STYLE_NORMAL
;
3140 } /* TODO: give error if unknow style is chosen */
3142 switch (hi
->userlist_style
) {
3143 case HI_STYLE_ADVANCED
:
3146 case HI_STYLE_CLASSIC
:
3149 case HI_STYLE_CLEAN
:
3152 case HI_STYLE_NORMAL
:
3157 reply("NSMSG_SET_STYLE", style
);
3161 static OPTION_FUNC(opt_announcements
)
3166 if (enabled_string(argv
[1]))
3167 hi
->announcements
= 'y';
3168 else if (disabled_string(argv
[1]))
3169 hi
->announcements
= 'n';
3170 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
3171 hi
->announcements
= '?';
3173 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
3178 switch (hi
->announcements
) {
3179 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
3180 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
3181 case '?': choice
= "default"; break;
3182 default: choice
= "unknown"; break;
3184 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
3188 static OPTION_FUNC(opt_password
)
3190 char crypted
[MD5_CRYPT_LENGTH
+1];
3195 reply("NSMSG_USE_CMD_PASS");
3199 cryptpass(argv
[1], crypted
);
3201 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3203 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
3204 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3209 strcpy(hi
->passwd
, crypted
);
3210 if (nickserv_conf
.sync_log
)
3211 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
3213 reply("NSMSG_SET_PASSWORD", "***");
3217 static OPTION_FUNC(opt_flags
)
3220 unsigned int ii
, flen
;
3223 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3228 nickserv_apply_flags(user
, hi
, argv
[1]);
3230 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
3231 if (hi
->flags
& (1 << ii
))
3232 flags
[flen
++] = handle_flags
[ii
];
3235 reply("NSMSG_SET_FLAGS", flags
);
3237 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
3241 static OPTION_FUNC(opt_email
)
3245 if (!valid_email(argv
[1])) {
3246 reply("NSMSG_BAD_EMAIL_ADDR");
3249 if ((str
= mail_prohibited_address(argv
[1]))) {
3250 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
3253 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
3254 reply("NSMSG_EMAIL_SAME");
3256 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
3259 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3261 if((rc
= ldap_do_modify(hi
->handle
, NULL
, argv
[1])) != LDAP_SUCCESS
) {
3262 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3267 nickserv_set_email_addr(hi
, argv
[1]);
3269 nickserv_eat_cookie(hi
->cookie
);
3270 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3273 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3277 static OPTION_FUNC(opt_maxlogins
)
3279 unsigned char maxlogins
;
3281 maxlogins
= strtoul(argv
[1], NULL
, 0);
3282 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
3283 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
3286 hi
->maxlogins
= maxlogins
;
3288 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
3289 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
3293 static OPTION_FUNC(opt_advanced
)
3296 if (enabled_string(argv
[1]))
3297 HANDLE_SET_FLAG(hi
, ADVANCED
);
3298 else if (disabled_string(argv
[1]))
3299 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
3301 reply("MSG_INVALID_BINARY", argv
[1]);
3306 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
3310 static OPTION_FUNC(opt_language
)
3312 struct language
*lang
;
3314 lang
= language_find(argv
[1]);
3315 if (irccasecmp(lang
->name
, argv
[1]))
3316 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
3317 hi
->language
= lang
;
3319 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
3323 static OPTION_FUNC(opt_karma
)
3326 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3331 if (argv
[1][0] == '+' && isdigit(argv
[1][1])) {
3332 hi
->karma
+= strtoul(argv
[1] + 1, NULL
, 10);
3333 } else if (argv
[1][0] == '-' && isdigit(argv
[1][1])) {
3334 hi
->karma
-= strtoul(argv
[1] + 1, NULL
, 10);
3336 send_message(user
, nickserv
, "NSMSG_INVALID_KARMA", argv
[1]);
3340 send_message(user
, nickserv
, "NSMSG_SET_KARMA", hi
->karma
);
3344 /* Called from opserv from cmd_access */
3346 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
3347 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
3349 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
3350 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
3351 && (user
->handle_info
->opserv_level
< 1000))) {
3352 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
3355 if ((user
->handle_info
->opserv_level
< new_level
)
3356 || ((user
->handle_info
->opserv_level
== new_level
)
3357 && (user
->handle_info
->opserv_level
< 1000))) {
3358 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
3361 if (user
->handle_info
== target
) {
3362 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
3366 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_oper_group_dn
) && *(nickserv_conf
.ldap_admin_dn
)) {
3368 if(new_level
> nickserv_conf
.ldap_oper_group_level
)
3369 rc
= ldap_add2group(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3371 rc
= ldap_delfromgroup(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3372 if(rc
!= LDAP_SUCCESS
&& rc
!= LDAP_TYPE_OR_VALUE_EXISTS
&& rc
!= LDAP_NO_SUCH_ATTRIBUTE
) {
3373 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3377 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_field_oslevel
) && *(nickserv_conf
.ldap_admin_dn
)) {
3379 if((rc
= ldap_do_oslevel(target
->handle
, new_level
)) != LDAP_SUCCESS
) {
3380 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3385 if (target
->opserv_level
== new_level
)
3387 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
3388 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
3389 target
->opserv_level
= new_level
;
3393 static OPTION_FUNC(opt_level
)
3398 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3402 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
3403 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
3407 static OPTION_FUNC(opt_epithet
)
3409 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
3411 struct userNode
*target
, *next_un
;
3414 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3418 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
3422 if ((epithet
[0] == '*') && !epithet
[1])
3425 hi
->epithet
= strdup(epithet
);
3427 for (target
= hi
->users
; target
; target
= next_un
) {
3428 irc_swhois(nickserv
, target
, hi
->epithet
);
3430 next_un
= target
->next_authed
;
3435 reply("NSMSG_SET_EPITHET", hi
->epithet
);
3437 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
3441 static OPTION_FUNC(opt_title
)
3447 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
3449 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3454 if(!strcmp(title
, "*")) {
3456 hi
->fakehost
= NULL
;
3459 if (strchr(title
, '.')) {
3460 reply("NSMSG_TITLE_INVALID");
3463 /* Alphanumeric titles only. */
3464 for(sptr
= title
; *sptr
; sptr
++) {
3465 if(!isalnum(*sptr
) && *sptr
!= '-') {
3466 reply("NSMSG_TITLE_INVALID");
3470 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
3471 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3472 reply("NSMSG_TITLE_TRUNCATED");
3476 hi
->fakehost
= malloc(strlen(title
)+2);
3477 hi
->fakehost
[0] = '.';
3478 strcpy(hi
->fakehost
+1, title
);
3481 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3482 title
= hi
->fakehost
+ 1;
3484 /* If theres no title set then the default title will therefore
3485 be the first part of hidden_host in x3.conf, so for
3486 consistency with opt_fakehost we will print this here.
3487 This isnt actually used in P10, its just handled to keep from crashing... */
3488 char *hs
, *hidden_suffix
, *rest
;
3490 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3491 hidden_suffix
= strdup(hs
);
3493 /* Yes we do this twice */
3494 if((rest
= strchr(hidden_suffix
, '.')))
3497 title
= hidden_suffix
;
3501 /* A lame default if someone configured hidden_host to something lame */
3502 title
= strdup("users");
3503 free(hidden_suffix
);
3509 none
= user_find_message(user
, "MSG_NONE");
3510 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3515 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3519 // check for a dot in the vhost
3520 if(strchr(vhost
, '.') == NULL
) {
3521 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3525 // check for a @ in the vhost
3526 if(strchr(vhost
, '@') != NULL
) {
3527 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3531 // check for denied words, inspired by monk at paki.sex
3532 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3533 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3534 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3539 // check for ircu's HOSTLEN length.
3540 if(strlen(vhost
) >= HOSTLEN
) {
3541 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3545 /* This can be handled by the regex now if desired.
3546 if (vhost[strspn(vhost, "0123456789.")]) {
3547 hostname = vhost + strlen(vhost);
3548 for (depth = 1; depth && (hostname > vhost); depth--) {
3550 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3553 if (*hostname == '.') hostname++; * advance past last dot we saw *
3554 if(strlen(hostname) > 4) {
3555 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3560 /* test either regex or as valid handle */
3561 if (nickserv_conf
.valid_fakehost_regex_set
) {
3562 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3565 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3566 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3568 if(err
== REG_NOMATCH
) {
3569 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3578 static OPTION_FUNC(opt_fakehost
)
3582 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3584 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3589 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3590 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3593 if (!strcmp(fake
, "*")) {
3596 hi
->fakehost
= NULL
;
3599 else if (!check_vhost(argv
[1], user
, cmd
)) {
3600 /* check_vhost takes care of error reply */
3606 hi
->fakehost
= strdup(fake
);
3609 fake
= hi
->fakehost
;
3611 fake
= generate_fakehost(hi
);
3613 /* Tell them we set the host */
3615 fake
= user_find_message(user
, "MSG_NONE");
3616 reply("NSMSG_SET_FAKEHOST", fake
);
3620 static OPTION_FUNC(opt_note
)
3623 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3628 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3633 if ((text
[0] == '*') && !text
[1])
3636 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3641 reply("NSMSG_SET_NOTE", hi
->note
? hi
->note
->note
: user_find_message(user
, "MSG_NONE"));
3645 static NICKSERV_FUNC(cmd_reclaim
)
3647 struct handle_info
*hi
;
3648 struct nick_info
*ni
;
3649 struct userNode
*victim
;
3651 NICKSERV_MIN_PARMS(2);
3652 hi
= user
->handle_info
;
3653 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3655 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3658 if (ni
->owner
!= user
->handle_info
) {
3659 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3662 victim
= GetUserH(ni
->nick
);
3664 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3667 if (victim
== user
) {
3668 reply("NSMSG_NICK_USER_YOU");
3671 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3672 switch (nickserv_conf
.reclaim_action
) {
3673 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3674 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3675 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3676 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3681 static NICKSERV_FUNC(cmd_unregnick
)
3684 struct handle_info
*hi
;
3685 struct nick_info
*ni
;
3687 hi
= user
->handle_info
;
3688 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3689 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3691 reply("NSMSG_UNKNOWN_NICK", nick
);
3694 if (hi
!= ni
->owner
) {
3695 reply("NSMSG_NOT_YOUR_NICK", nick
);
3698 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3703 static NICKSERV_FUNC(cmd_ounregnick
)
3705 struct nick_info
*ni
;
3707 NICKSERV_MIN_PARMS(2);
3708 if (!(ni
= get_nick_info(argv
[1]))) {
3709 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3712 if (!oper_outranks(user
, ni
->owner
))
3714 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3719 static NICKSERV_FUNC(cmd_unregister
)
3721 struct handle_info
*hi
;
3724 NICKSERV_MIN_PARMS(2);
3725 hi
= user
->handle_info
;
3728 if (checkpass(passwd
, hi
->passwd
)) {
3729 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3734 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3735 reply("NSMSG_PASSWORD_INVALID");
3740 static NICKSERV_FUNC(cmd_ounregister
)
3742 struct handle_info
*hi
;
3743 char reason
[MAXLEN
];
3746 NICKSERV_MIN_PARMS(2);
3747 if (!(hi
= get_victim_oper(user
, argv
[1])))
3750 if (HANDLE_FLAGGED(hi
, NODELETE
)) {
3751 reply("NSMSG_UNREGISTER_NODELETE", hi
->handle
);
3755 force
= IsOper(user
) && (argc
> 2) && !irccasecmp(argv
[2], "force");
3757 ((hi
->flags
& nickserv_conf
.ounregister_flags
)
3759 || (hi
->last_quit_host
[0] && ((unsigned)(now
- hi
->lastseen
) < nickserv_conf
.ounregister_inactive
)))) {
3760 reply((IsOper(user
) ? "NSMSG_UNREGISTER_MUST_FORCE" : "NSMSG_UNREGISTER_CANNOT_FORCE"), hi
->handle
);
3763 snprintf(reason
, sizeof(reason
), "%s unregistered account %s.", user
->handle_info
->handle
, hi
->handle
);
3764 global_message(MESSAGE_RECIPIENT_STAFF
, reason
);
3765 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3771 static NICKSERV_FUNC(cmd_status
)
3773 if (nickserv_conf
.disable_nicks
) {
3774 reply("NSMSG_GLOBAL_STATS_NONICK",
3775 dict_size(nickserv_handle_dict
));
3777 if (user
->handle_info
) {
3779 struct nick_info
*ni
;
3780 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3781 reply("NSMSG_HANDLE_STATS", cnt
);
3783 reply("NSMSG_HANDLE_NONE");
3785 reply("NSMSG_GLOBAL_STATS",
3786 dict_size(nickserv_handle_dict
),
3787 dict_size(nickserv_nick_dict
));
3792 static NICKSERV_FUNC(cmd_ghost
)
3794 struct userNode
*target
;
3795 char reason
[MAXLEN
];
3797 NICKSERV_MIN_PARMS(2);
3798 if (!(target
= GetUserH(argv
[1]))) {
3799 reply("MSG_NICK_UNKNOWN", argv
[1]);
3802 if (target
== user
) {
3803 reply("NSMSG_CANNOT_GHOST_SELF");
3806 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3807 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3810 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3811 DelUser(target
, nickserv
, 1, reason
);
3812 reply("NSMSG_GHOST_KILLED", argv
[1]);
3816 static NICKSERV_FUNC(cmd_vacation
)
3818 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3819 reply("NSMSG_ON_VACATION");
3824 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3826 struct handle_info
*hi
;
3829 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3831 saxdb_start_record(ctx
, iter_key(it
), 0);
3832 if (hi
->announcements
!= '?') {
3833 flags
[0] = hi
->announcements
;
3835 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3838 struct handle_cookie
*cookie
= hi
->cookie
;
3841 switch (cookie
->type
) {
3842 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3843 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3844 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3845 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3846 default: type
= NULL
; break;
3849 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3850 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3851 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3853 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3854 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3855 saxdb_end_record(ctx
);
3859 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3861 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3863 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3864 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3865 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3866 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3867 saxdb_end_record(ctx
);
3871 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3875 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3876 if (hi
->flags
& (1 << ii
))
3877 flags
[flen
++] = handle_flags
[ii
];
3879 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3882 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3883 if (hi
->last_quit_host
[0])
3884 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3885 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3887 saxdb_write_sint(ctx
, KEY_KARMA
, hi
->karma
);
3888 if (hi
->masks
->used
)
3889 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3890 if (hi
->ignores
->used
)
3891 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3893 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3895 struct string_list
*slist
;
3896 struct nick_info
*ni
;
3898 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3899 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3900 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3904 if (hi
->opserv_level
)
3905 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3906 if (hi
->language
!= lang_C
)
3907 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3908 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3909 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3910 if (hi
->screen_width
)
3911 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3912 if (hi
->table_width
)
3913 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3914 flags
[0] = hi
->userlist_style
;
3916 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3917 saxdb_end_record(ctx
);
3923 static handle_merge_func_t
*handle_merge_func_list
;
3924 static void **handle_merge_func_list_extra
;
3925 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3928 reg_handle_merge_func(handle_merge_func_t func
, void *extra
)
3930 if (handle_merge_func_used
== handle_merge_func_size
) {
3931 if (handle_merge_func_size
) {
3932 handle_merge_func_size
<<= 1;
3933 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3934 handle_merge_func_list_extra
= realloc(handle_merge_func_list_extra
, handle_merge_func_size
*sizeof(void*));
3936 handle_merge_func_size
= 8;
3937 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3938 handle_merge_func_list_extra
= malloc(handle_merge_func_size
*sizeof(void*));
3941 handle_merge_func_list
[handle_merge_func_used
] = func
;
3942 handle_merge_func_list_extra
[handle_merge_func_used
++] = extra
;
3945 static NICKSERV_FUNC(cmd_merge
)
3947 struct handle_info
*hi_from
, *hi_to
;
3948 struct userNode
*last_user
;
3949 struct userData
*cList
, *cListNext
;
3950 unsigned int ii
, jj
, n
;
3952 NICKSERV_MIN_PARMS(3);
3954 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3956 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3958 if (hi_to
== hi_from
) {
3959 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3963 for (n
=0; n
<handle_merge_func_used
; n
++)
3964 handle_merge_func_list
[n
](user
, hi_to
, hi_from
, handle_merge_func_list_extra
[n
]);
3966 /* Append "from" handle's nicks to "to" handle's nick list. */
3968 struct nick_info
*last_ni
;
3969 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3970 last_ni
->next
= hi_from
->nicks
;
3972 while (hi_from
->nicks
) {
3973 hi_from
->nicks
->owner
= hi_to
;
3974 hi_from
->nicks
= hi_from
->nicks
->next
;
3977 /* Merge the hostmasks. */
3978 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3979 char *mask
= hi_from
->masks
->list
[ii
];
3980 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3981 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3983 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3984 string_list_append(hi_to
->masks
, strdup(mask
));
3987 /* Merge the ignores. */
3988 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3989 char *ignore
= hi_from
->ignores
->list
[ii
];
3990 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3991 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3993 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3994 string_list_append(hi_to
->ignores
, strdup(ignore
));
3997 /* Merge the lists of authed users. */
3999 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
4000 last_user
->next_authed
= hi_from
->users
;
4002 hi_to
->users
= hi_from
->users
;
4004 /* Repoint the old "from" handle's users. */
4005 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
4006 last_user
->handle_info
= hi_to
;
4008 hi_from
->users
= NULL
;
4010 /* Merge channel userlists. */
4011 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
4012 struct userData
*cList2
;
4013 cListNext
= cList
->u_next
;
4014 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
4015 if (cList
->channel
== cList2
->channel
)
4017 if (cList2
&& (cList2
->access
>= cList
->access
)) {
4018 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
);
4019 /* keep cList2 in hi_to; remove cList from hi_from */
4020 del_channel_user(cList
, 1);
4023 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
);
4024 /* remove the lower-ranking cList2 from hi_to */
4025 del_channel_user(cList2
, 1);
4027 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
4029 /* cList needs to be moved from hi_from to hi_to */
4030 cList
->handle
= hi_to
;
4031 /* Remove from linked list for hi_from */
4032 assert(!cList
->u_prev
);
4033 hi_from
->channels
= cList
->u_next
;
4035 cList
->u_next
->u_prev
= cList
->u_prev
;
4036 /* Add to linked list for hi_to */
4037 cList
->u_prev
= NULL
;
4038 cList
->u_next
= hi_to
->channels
;
4039 if (hi_to
->channels
)
4040 hi_to
->channels
->u_prev
= cList
;
4041 hi_to
->channels
= cList
;
4045 /* Do they get an OpServ level promotion? */
4046 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
4047 hi_to
->opserv_level
= hi_from
->opserv_level
;
4049 /* What about last seen time? */
4050 if (hi_from
->lastseen
> hi_to
->lastseen
)
4051 hi_to
->lastseen
= hi_from
->lastseen
;
4053 /* New karma is the sum of the two original karmas. */
4054 hi_to
->karma
+= hi_from
->karma
;
4056 /* Does a fakehost carry over? (This intentionally doesn't set it
4057 * for users previously attached to hi_to. They'll just have to
4060 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
4061 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
4063 /* Notify of success. */
4064 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
4065 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
4066 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
4068 /* Unregister the "from" handle. */
4069 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
4070 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
4071 * the process isn't completed.
4077 struct nickserv_discrim
{
4078 unsigned long flags_on
, flags_off
;
4079 time_t min_registered
, max_registered
;
4082 int min_level
, max_level
;
4083 int min_karma
, max_karma
;
4084 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
4085 const char *nickmask
;
4086 const char *hostmask
;
4087 const char *handlemask
;
4088 const char *emailmask
;
4090 unsigned int inldap
;
4094 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
4096 struct discrim_apply_info
{
4097 struct nickserv_discrim
*discrim
;
4098 discrim_search_func func
;
4099 struct userNode
*source
;
4100 unsigned int matched
;
4103 static struct nickserv_discrim
*
4104 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
4107 struct nickserv_discrim
*discrim
;
4109 discrim
= malloc(sizeof(*discrim
));
4110 memset(discrim
, 0, sizeof(*discrim
));
4111 discrim
->min_level
= 0;
4112 discrim
->max_level
= INT_MAX
;
4113 discrim
->limit
= 50;
4114 discrim
->min_registered
= 0;
4115 discrim
->max_registered
= INT_MAX
;
4116 discrim
->lastseen
= LONG_MAX
;
4117 discrim
->min_karma
= INT_MIN
;
4118 discrim
->max_karma
= INT_MAX
;
4120 discrim
->inldap
= 2;
4123 for (i
=0; i
<argc
; i
++) {
4124 if (i
== argc
- 1) {
4125 reply("MSG_MISSING_PARAMS", argv
[i
]);
4128 if (!irccasecmp(argv
[i
], "limit")) {
4129 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
4130 } else if (!irccasecmp(argv
[i
], "flags")) {
4131 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
4132 } else if (!irccasecmp(argv
[i
], "registered")) {
4133 const char *cmp
= argv
[++i
];
4134 if (cmp
[0] == '<') {
4135 if (cmp
[1] == '=') {
4136 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
4138 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
4140 } else if (cmp
[0] == '=') {
4141 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
4142 } else if (cmp
[0] == '>') {
4143 if (cmp
[1] == '=') {
4144 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
4146 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
4149 reply("MSG_INVALID_CRITERIA", cmp
);
4151 } else if (!irccasecmp(argv
[i
], "seen")) {
4152 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
4153 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
4154 discrim
->nickmask
= argv
[++i
];
4155 } else if (!irccasecmp(argv
[i
], "hostmask")) {
4157 if (!irccasecmp(argv
[i
], "exact")) {
4158 if (i
== argc
- 1) {
4159 reply("MSG_MISSING_PARAMS", argv
[i
]);
4162 discrim
->hostmask_type
= EXACT
;
4163 } else if (!irccasecmp(argv
[i
], "subset")) {
4164 if (i
== argc
- 1) {
4165 reply("MSG_MISSING_PARAMS", argv
[i
]);
4168 discrim
->hostmask_type
= SUBSET
;
4169 } else if (!irccasecmp(argv
[i
], "superset")) {
4170 if (i
== argc
- 1) {
4171 reply("MSG_MISSING_PARAMS", argv
[i
]);
4174 discrim
->hostmask_type
= SUPERSET
;
4175 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
4176 if (i
== argc
- 1) {
4177 reply("MSG_MISSING_PARAMS", argv
[i
]);
4180 discrim
->hostmask_type
= LASTQUIT
;
4183 discrim
->hostmask_type
= SUPERSET
;
4185 discrim
->hostmask
= argv
[++i
];
4186 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask") || !irccasecmp(argv
[i
], "account")) {
4187 if (!irccasecmp(argv
[++i
], "*")) {
4188 discrim
->handlemask
= 0;
4190 discrim
->handlemask
= argv
[i
];
4192 } else if (!irccasecmp(argv
[i
], "email")) {
4193 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
4194 reply("MSG_NO_SEARCH_ACCESS", "email");
4196 } else if (!irccasecmp(argv
[++i
], "*")) {
4197 discrim
->emailmask
= 0;
4199 discrim
->emailmask
= argv
[i
];
4201 } else if (!irccasecmp(argv
[i
], "access")) {
4202 const char *cmp
= argv
[++i
];
4203 if (cmp
[0] == '<') {
4204 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
4205 if (cmp
[1] == '=') {
4206 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
4208 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
4210 } else if (cmp
[0] == '=') {
4211 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
4212 } else if (cmp
[0] == '>') {
4213 if (cmp
[1] == '=') {
4214 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
4216 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
4219 reply("MSG_INVALID_CRITERIA", cmp
);
4221 } else if (!irccasecmp(argv
[i
], "karma")) {
4222 const char *cmp
= argv
[++i
];
4223 if (cmp
[0] == '<') {
4224 if (cmp
[1] == '=') {
4225 discrim
->max_karma
= strtoul(cmp
+2, NULL
, 0);
4227 discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0) - 1;
4229 } else if (cmp
[0] == '=') {
4230 discrim
->min_karma
= discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0);
4231 } else if (cmp
[0] == '>') {
4232 if (cmp
[1] == '=') {
4233 discrim
->min_karma
= strtoul(cmp
+2, NULL
, 0);
4235 discrim
->min_karma
= strtoul(cmp
+1, NULL
, 0) + 1;
4238 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
4241 } else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[i
], "inldap")) {
4243 if(true_string(argv
[i
])) {
4244 discrim
->inldap
= 1;
4246 else if (false_string(argv
[i
])) {
4247 discrim
->inldap
= 0;
4250 reply("MSG_INVALID_BINARY", argv
[i
]);
4254 reply("MSG_INVALID_CRITERIA", argv
[i
]);
4265 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
4267 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
4268 || (discrim
->flags_off
& hi
->flags
)
4269 || (discrim
->min_registered
> hi
->registered
)
4270 || (discrim
->max_registered
< hi
->registered
)
4271 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
4272 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
4273 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
4274 || (discrim
->min_level
> hi
->opserv_level
)
4275 || (discrim
->max_level
< hi
->opserv_level
)
4276 || (discrim
->min_karma
> hi
->karma
)
4277 || (discrim
->max_karma
< hi
->karma
)
4281 if (discrim
->hostmask
) {
4283 for (i
=0; i
<hi
->masks
->used
; i
++) {
4284 const char *mask
= hi
->masks
->list
[i
];
4285 if ((discrim
->hostmask_type
== SUBSET
)
4286 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
4287 else if ((discrim
->hostmask_type
== EXACT
)
4288 && !irccasecmp(discrim
->hostmask
, mask
)) break;
4289 else if ((discrim
->hostmask_type
== SUPERSET
)
4290 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
4291 else if ((discrim
->hostmask_type
== LASTQUIT
)
4292 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
4294 if (i
==hi
->masks
->used
) return 0;
4296 if (discrim
->nickmask
) {
4297 struct nick_info
*nick
= hi
->nicks
;
4299 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
4302 if (!nick
) return 0;
4305 if(nickserv_conf
.ldap_enable
&& discrim
->inldap
!= 2) {
4307 rc
= ldap_get_user_info(hi
->handle
, NULL
);
4308 if(discrim
->inldap
== 1 && rc
!= LDAP_SUCCESS
)
4310 if(discrim
->inldap
== 0 && rc
== LDAP_SUCCESS
)
4319 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
4321 dict_iterator_t it
, next
;
4322 unsigned int matched
;
4324 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
4325 it
&& (matched
< discrim
->limit
);
4327 next
= iter_next(it
);
4328 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
4329 dsf(source
, iter_data(it
));
4337 search_print_func(struct userNode
*source
, struct handle_info
*match
)
4339 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
4343 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
4348 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
4350 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
4351 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
4356 search_add2ldap_func (struct userNode
*source
, struct handle_info
*match
)
4359 if(match
->email_addr
&& match
->passwd
&& match
->handle
) {
4360 rc
= ldap_do_add(match
->handle
, match
->passwd
, match
->email_addr
);
4361 if(rc
!= LDAP_SUCCESS
) {
4362 send_message(source
, nickserv
, "NSMSG_LDAP_FAIL_ADD", match
->handle
, ldap_err2string(rc
));
4369 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
4371 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
4372 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
4373 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
4374 return hi_b
->opserv_level
- hi_a
->opserv_level
;
4375 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
4379 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
4381 struct handle_info_list hil
;
4382 struct helpfile_table tbl
;
4387 memset(&hil
, 0, sizeof(hil
));
4388 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
4389 struct handle_info
*hi
= iter_data(it
);
4390 if (hi
->opserv_level
)
4391 handle_info_list_append(&hil
, hi
);
4393 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
4394 tbl
.length
= hil
.used
+ 1;
4396 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
4397 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
4398 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4401 for (ii
= 0; ii
< hil
.used
; ) {
4402 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4403 ary
[0] = hil
.list
[ii
]->handle
;
4404 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
4405 tbl
.contents
[++ii
] = ary
;
4407 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4408 /*reply("MSG_MATCH_COUNT", hil.used); */
4409 for (ii
= 0; ii
< hil
.used
; ii
++)
4410 free(tbl
.contents
[ii
]);
4415 static NICKSERV_FUNC(cmd_search
)
4417 struct nickserv_discrim
*discrim
;
4418 discrim_search_func action
;
4419 struct svccmd
*subcmd
;
4420 unsigned int matches
;
4423 NICKSERV_MIN_PARMS(3);
4424 sprintf(buf
, "search %s", argv
[1]);
4425 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
4426 if (!irccasecmp(argv
[1], "print"))
4427 action
= search_print_func
;
4428 else if (!irccasecmp(argv
[1], "count"))
4429 action
= search_count_func
;
4430 else if (!irccasecmp(argv
[1], "unregister"))
4431 action
= search_unregister_func
;
4433 else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[1], "add2ldap"))
4434 action
= search_add2ldap_func
;
4437 reply("NSMSG_INVALID_ACTION", argv
[1]);
4441 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
4444 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
4448 if (action
== search_print_func
)
4449 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4450 else if (action
== search_count_func
)
4451 discrim
->limit
= INT_MAX
;
4453 matches
= nickserv_discrim_search(discrim
, action
, user
);
4456 reply("MSG_MATCH_COUNT", matches
);
4458 reply("MSG_NO_MATCHES");
4464 static MODCMD_FUNC(cmd_checkpass
)
4466 struct handle_info
*hi
;
4468 NICKSERV_MIN_PARMS(3);
4469 if (!(hi
= get_handle_info(argv
[1]))) {
4470 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
4473 if (checkpass(argv
[2], hi
->passwd
))
4474 reply("CHECKPASS_YES");
4476 reply("CHECKPASS_NO");
4481 static MODCMD_FUNC(cmd_checkemail
)
4483 struct handle_info
*hi
;
4485 NICKSERV_MIN_PARMS(3);
4486 if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
4489 if (!hi
->email_addr
)
4490 reply("CHECKEMAIL_NOT_SET");
4491 else if (!irccasecmp(argv
[2], hi
->email_addr
))
4492 reply("CHECKEMAIL_YES");
4494 reply("CHECKEMAIL_NO");
4499 nickserv_db_read_handle(char *handle
, dict_t obj
)
4502 struct string_list
*masks
, *slist
, *ignores
;
4503 struct handle_info
*hi
;
4504 struct userNode
*authed_users
;
4505 struct userData
*channel_list
;
4506 unsigned long int id
;
4509 char *setter
, *note
;
4512 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
4513 id
= str
? strtoul(str
, NULL
, 0) : 0;
4514 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
4516 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
4519 if ((hi
= get_handle_info(handle
))) {
4520 authed_users
= hi
->users
;
4521 channel_list
= hi
->channels
;
4523 hi
->channels
= NULL
;
4524 dict_remove(nickserv_handle_dict
, hi
->handle
);
4526 authed_users
= NULL
;
4527 channel_list
= NULL
;
4529 if(nickserv_conf
.force_handles_lowercase
)
4530 irc_strtolower(handle
);
4531 hi
= register_handle(handle
, str
, id
);
4533 hi
->users
= authed_users
;
4534 while (authed_users
) {
4535 authed_users
->handle_info
= hi
;
4536 authed_users
= authed_users
->next_authed
;
4539 hi
->channels
= channel_list
;
4540 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
4541 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
4542 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
4543 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
4544 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
4545 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
4546 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
4547 hi
->language
= language_find(str
? str
: "C");
4548 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
4549 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
4550 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
4552 hi
->infoline
= strdup(str
);
4553 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
4554 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4555 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
4556 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
4557 str
= database_get_data(obj
, KEY_KARMA
, RECDB_QSTRING
);
4558 hi
->karma
= str
? strtoul(str
, NULL
, 0) : 0;
4559 /* We want to read the nicks even if disable_nicks is set. This is so
4560 * that we don't lose the nick data entirely. */
4561 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
4563 for (ii
=0; ii
<slist
->used
; ii
++)
4564 register_nick(slist
->list
[ii
], hi
);
4566 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
4568 for (ii
=0; str
[ii
]; ii
++)
4569 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
4571 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
4572 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4573 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
4574 hi
->announcements
= str
? str
[0] : '?';
4575 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
4576 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
4577 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
4578 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
4579 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
4581 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
4583 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
4584 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
4586 nickserv_set_email_addr(hi
, str
);
4587 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
4589 hi
->epithet
= strdup(str
);
4590 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
4592 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
4593 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
4594 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4595 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
4596 if (setter
&& date
&& note
)
4598 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
4603 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
4605 hi
->fakehost
= strdup(str
);
4607 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4609 const char *data
, *type
, *expires
, *cookie_str
;
4610 struct handle_cookie
*cookie
;
4612 cookie
= calloc(1, sizeof(*cookie
));
4613 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4614 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4615 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4616 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4617 if (!type
|| !expires
|| !cookie_str
) {
4618 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4621 if (!irccasecmp(type
, KEY_ACTIVATION
))
4622 cookie
->type
= ACTIVATION
;
4623 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4624 cookie
->type
= PASSWORD_CHANGE
;
4625 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4626 cookie
->type
= EMAIL_CHANGE
;
4627 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4628 cookie
->type
= ALLOWAUTH
;
4630 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4633 cookie
->expires
= strtoul(expires
, NULL
, 0);
4634 if (cookie
->expires
< now
)
4637 cookie
->data
= strdup(data
);
4638 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4642 nickserv_bake_cookie(cookie
);
4644 nickserv_free_cookie(cookie
);
4649 nickserv_saxdb_read(dict_t db
) {
4651 struct record_data
*rd
;
4654 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4656 handle
= strdup(iter_key(it
));
4657 nickserv_db_read_handle(handle
, rd
->d
.object
);
4663 static NICKSERV_FUNC(cmd_mergedb
)
4665 struct timeval start
, stop
;
4668 NICKSERV_MIN_PARMS(2);
4669 gettimeofday(&start
, NULL
);
4670 if (!(db
= parse_database(argv
[1]))) {
4671 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4674 nickserv_saxdb_read(db
);
4676 gettimeofday(&stop
, NULL
);
4677 stop
.tv_sec
-= start
.tv_sec
;
4678 stop
.tv_usec
-= start
.tv_usec
;
4679 if (stop
.tv_usec
< 0) {
4681 stop
.tv_usec
+= 1000000;
4683 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4688 expire_handles(UNUSED_ARG(void *data
))
4690 dict_iterator_t it
, next
;
4692 struct handle_info
*hi
;
4694 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4695 next
= iter_next(it
);
4697 if ((hi
->opserv_level
> 0)
4699 || HANDLE_FLAGGED(hi
, FROZEN
)
4700 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4703 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4704 if ((now
- hi
->lastseen
) > expiry
) {
4705 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4706 nickserv_unregister_handle(hi
, NULL
, NULL
);
4710 if (nickserv_conf
.handle_expire_frequency
)
4711 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4715 nickserv_load_dict(const char *fname
)
4719 if (!(file
= fopen(fname
, "r"))) {
4720 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4723 while (fgets(line
, sizeof(line
), file
)) {
4726 if (line
[strlen(line
)-1] == '\n')
4727 line
[strlen(line
)-1] = 0;
4728 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4731 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4734 static enum reclaim_action
4735 reclaim_action_from_string(const char *str
) {
4737 return RECLAIM_NONE
;
4738 else if (!irccasecmp(str
, "warn"))
4739 return RECLAIM_WARN
;
4740 else if (!irccasecmp(str
, "svsnick"))
4741 return RECLAIM_SVSNICK
;
4742 else if (!irccasecmp(str
, "kill"))
4743 return RECLAIM_KILL
;
4745 return RECLAIM_NONE
;
4749 nickserv_conf_read(void)
4751 dict_t conf_node
, child
;
4754 struct string_list
*strlist
;
4756 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4757 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4760 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4762 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4763 if (nickserv_conf
.valid_handle_regex_set
)
4764 regfree(&nickserv_conf
.valid_handle_regex
);
4766 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4767 nickserv_conf
.valid_handle_regex_set
= !err
;
4768 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4770 nickserv_conf
.valid_handle_regex_set
= 0;
4772 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4773 if (nickserv_conf
.valid_nick_regex_set
)
4774 regfree(&nickserv_conf
.valid_nick_regex
);
4776 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4777 nickserv_conf
.valid_nick_regex_set
= !err
;
4778 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4780 nickserv_conf
.valid_nick_regex_set
= 0;
4782 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4783 if (nickserv_conf
.valid_fakehost_regex_set
)
4784 regfree(&nickserv_conf
.valid_fakehost_regex
);
4786 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4787 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4788 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4790 nickserv_conf
.valid_fakehost_regex_set
= 0;
4792 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4794 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4795 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4796 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4797 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4798 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4799 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4800 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4801 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4802 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4803 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4804 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4805 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4806 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4807 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4808 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4809 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4810 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4811 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4812 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4813 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4814 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4815 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4816 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4817 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4818 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4820 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4821 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4822 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4824 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4825 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4826 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4828 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4829 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4830 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4831 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4832 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4833 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4834 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4835 str
= database_get_data(conf_node
, KEY_OUNREGISTER_INACTIVE
, RECDB_QSTRING
);
4836 nickserv_conf
.ounregister_inactive
= str
? ParseInterval(str
) : 86400*28;
4837 str
= database_get_data(conf_node
, KEY_OUNREGISTER_FLAGS
, RECDB_QSTRING
);
4840 nickserv_conf
.ounregister_flags
= 0;
4842 unsigned int pos
= handle_inverse_flags
[(unsigned char)*str
];
4845 nickserv_conf
.ounregister_flags
|= 1 << (pos
- 1);
4847 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4848 if (!nickserv_conf
.disable_nicks
) {
4849 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4850 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4851 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4852 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4853 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4854 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4855 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4856 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4858 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4859 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4860 const char *key
= iter_key(it
), *value
;
4864 if (!strncasecmp(key
, "uc_", 3))
4865 flag
= toupper(key
[3]);
4866 else if (!strncasecmp(key
, "lc_", 3))
4867 flag
= tolower(key
[3]);
4871 if ((pos
= handle_inverse_flags
[flag
])) {
4872 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4873 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4876 if (nickserv_conf
.weak_password_dict
)
4877 dict_delete(nickserv_conf
.weak_password_dict
);
4878 nickserv_conf
.weak_password_dict
= dict_new();
4879 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4880 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4881 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4882 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4884 nickserv_load_dict(str
);
4885 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4886 if (nickserv
&& str
)
4887 NickChange(nickserv
, str
, 0);
4888 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4889 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4890 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4891 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4892 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4893 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4894 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4895 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4896 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4897 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4898 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4899 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4900 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4901 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4902 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4903 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4904 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4905 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4906 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4907 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4909 free_string_list(nickserv_conf
.denied_fakehost_words
);
4910 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4912 strlist
= string_list_copy(strlist
);
4914 strlist
= alloc_string_list(4);
4915 string_list_append(strlist
, strdup("sex"));
4916 string_list_append(strlist
, strdup("fuck"));
4918 nickserv_conf
.denied_fakehost_words
= strlist
;
4920 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4921 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4923 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4924 nickserv_conf
.auto_oper
= str
? str
: "";
4926 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4927 nickserv_conf
.auto_admin
= str
? str
: "";
4929 str
= database_get_data(conf_node
, KEY_AUTO_OPER_PRIVS
, RECDB_QSTRING
);
4930 nickserv_conf
.auto_oper_privs
= str
? str
: "";
4932 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN_PRIVS
, RECDB_QSTRING
);
4933 nickserv_conf
.auto_admin_privs
= str
? str
: "";
4935 str
= conf_get_data("server/network", RECDB_QSTRING
);
4936 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4937 if (!nickserv_conf
.auth_policer_params
) {
4938 nickserv_conf
.auth_policer_params
= policer_params_new();
4939 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4940 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4942 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4943 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4944 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4946 str
= database_get_data(conf_node
, KEY_LDAP_ENABLE
, RECDB_QSTRING
);
4947 nickserv_conf
.ldap_enable
= str
? strtoul(str
, NULL
, 0) : 0;
4949 str
= database_get_data(conf_node
, KEY_FORCE_HANDLES_LOWERCASE
, RECDB_QSTRING
);
4950 nickserv_conf
.force_handles_lowercase
= str
? strtol(str
, NULL
, 0) : 0;
4953 if(nickserv_conf
.ldap_enable
> 0) {
4954 /* ldap is enabled but not compiled in - error out */
4955 log_module(MAIN_LOG
, LOG_ERROR
, "ldap is enabled in config, but not compiled in!");
4956 nickserv_conf
.ldap_enable
= 0;
4962 str
= database_get_data(conf_node
, KEY_LDAP_URI
, RECDB_QSTRING
);
4963 nickserv_conf
.ldap_uri
= str
? str
: "";
4965 str
= database_get_data(conf_node
, KEY_LDAP_BASE
, RECDB_QSTRING
);
4966 nickserv_conf
.ldap_base
= str
? str
: "";
4968 str
= database_get_data(conf_node
, KEY_LDAP_DN_FMT
, RECDB_QSTRING
);
4969 nickserv_conf
.ldap_dn_fmt
= str
? str
: "";
4971 str
= database_get_data(conf_node
, KEY_LDAP_VERSION
, RECDB_QSTRING
);
4972 nickserv_conf
.ldap_version
= str
? strtoul(str
, NULL
, 0) : 3;
4974 str
= database_get_data(conf_node
, KEY_LDAP_AUTOCREATE
, RECDB_QSTRING
);
4975 nickserv_conf
.ldap_autocreate
= str
? strtoul(str
, NULL
, 0) : 0;
4977 str
= database_get_data(conf_node
, KEY_LDAP_TIMEOUT
, RECDB_QSTRING
);
4978 nickserv_conf
.ldap_timeout
= str
? strtoul(str
, NULL
, 0) : 5;
4980 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_DN
, RECDB_QSTRING
);
4981 nickserv_conf
.ldap_admin_dn
= str
? str
: "";
4983 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_PASS
, RECDB_QSTRING
);
4984 nickserv_conf
.ldap_admin_pass
= str
? str
: "";
4986 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_ACCOUNT
, RECDB_QSTRING
);
4987 nickserv_conf
.ldap_field_account
= str
? str
: "";
4989 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_PASSWORD
, RECDB_QSTRING
);
4990 nickserv_conf
.ldap_field_password
= str
? str
: "";
4992 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_EMAIL
, RECDB_QSTRING
);
4993 nickserv_conf
.ldap_field_email
= str
? str
: "";
4995 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_OSLEVEL
, RECDB_QSTRING
);
4996 nickserv_conf
.ldap_field_oslevel
= str
? str
: "";
4998 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_DN
, RECDB_QSTRING
);
4999 nickserv_conf
.ldap_oper_group_dn
= str
? str
: "";
5001 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_LEVEL
, RECDB_QSTRING
);
5002 nickserv_conf
.ldap_oper_group_level
= str
? strtoul(str
, NULL
, 0) : 99;
5004 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_GROUP_MEMBER
, RECDB_QSTRING
);
5005 nickserv_conf
.ldap_field_group_member
= str
? str
: "";
5007 free_string_list(nickserv_conf
.ldap_object_classes
);
5008 strlist
= database_get_data(conf_node
, KEY_LDAP_OBJECT_CLASSES
, RECDB_STRING_LIST
);
5010 strlist
= string_list_copy(strlist
);
5012 strlist
= alloc_string_list(4);
5013 string_list_append(strlist
, strdup("top"));
5015 nickserv_conf
.ldap_object_classes
= strlist
;
5022 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
5024 char newnick
[NICKLEN
+1];
5033 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
5034 send_message(user
, nickserv
, "NSMSG_RECLAIM_HOWTO", ni
->owner
->handle
, nickserv
->nick
, self
->name
, ni
->owner
->handle
);
5036 case RECLAIM_SVSNICK
:
5038 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
5039 } while (GetUserH(newnick
));
5040 irc_svsnick(nickserv
, user
, newnick
);
5043 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
5044 DelUser(user
, nickserv
, 1, msg
);
5050 nickserv_reclaim_p(void *data
) {
5051 struct userNode
*user
= data
;
5052 struct nick_info
*ni
= get_nick_info(user
->nick
);
5054 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5058 check_user_nick(struct userNode
*user
, UNUSED_ARG(void *extra
)) {
5059 struct nick_info
*ni
;
5060 user
->modes
&= ~FLAGS_REGNICK
;
5061 if (!(ni
= get_nick_info(user
->nick
)))
5063 if (user
->handle_info
== ni
->owner
) {
5064 user
->modes
|= FLAGS_REGNICK
;
5068 if (nickserv_conf
.warn_nick_owned
)
5069 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
5070 send_message(user
, nickserv
, "NSMSG_RECLAIM_HOWTO", ni
->owner
->handle
, nickserv
->nick
, self
->name
, ni
->owner
->handle
);
5071 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
5073 if (nickserv_conf
.auto_reclaim_delay
)
5074 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
5076 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5082 handle_account(struct userNode
*user
, const char *stamp
)
5084 struct handle_info
*hi
;
5087 #ifdef WITH_PROTOCOL_P10
5088 time_t timestamp
= 0;
5090 colon
= strchr(stamp
, ':');
5091 if(colon
&& colon
[1])
5094 timestamp
= atoi(colon
+1);
5096 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
5097 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
5099 log_module(MAIN_LOG
, LOG_WARNING
, "%s using account %s but timestamp does not match %s is not %s.", user
->nick
, stamp
, ctime(×tamp
),
5100 ctime(&hi
->registered
));
5104 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
5105 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
5109 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
5112 set_user_handle_info(user
, hi
, 0);
5114 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
5119 handle_nick_change(struct userNode
*user
, const char *old_nick
, UNUSED_ARG(void *extra
))
5121 struct handle_info
*hi
;
5123 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
5124 dict_remove(nickserv_allow_auth_dict
, old_nick
);
5125 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
5127 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5128 check_user_nick(user
, NULL
);
5132 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
), UNUSED_ARG(void *extra
))
5134 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
5135 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5136 set_user_handle_info(user
, NULL
, 0);
5139 static struct modcmd
*
5140 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
5142 if (min_level
> 0) {
5144 sprintf(buf
, "%u", min_level
);
5145 if (must_be_qualified
) {
5146 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
5148 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
5150 } else if (min_level
== 0) {
5151 if (must_be_qualified
) {
5152 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5154 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5157 if (must_be_qualified
) {
5158 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
5160 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
5166 nickserv_db_cleanup(void)
5168 unreg_del_user_func(nickserv_remove_user
, NULL
);
5169 userList_clean(&curr_helpers
);
5170 policer_params_delete(nickserv_conf
.auth_policer_params
);
5171 dict_delete(nickserv_handle_dict
);
5172 dict_delete(nickserv_nick_dict
);
5173 dict_delete(nickserv_opt_dict
);
5174 dict_delete(nickserv_allow_auth_dict
);
5175 dict_delete(nickserv_email_dict
);
5176 dict_delete(nickserv_id_dict
);
5177 dict_delete(nickserv_conf
.weak_password_dict
);
5178 free(auth_func_list
);
5179 free(unreg_func_list
);
5181 free(rf_list_extra
);
5182 free(allowauth_func_list
);
5183 free(allowauth_func_list_extra
);
5184 free(handle_merge_func_list
);
5185 free(handle_merge_func_list_extra
);
5186 free(failpw_func_list
);
5187 free(failpw_func_list_extra
);
5188 if (nickserv_conf
.valid_handle_regex_set
)
5189 regfree(&nickserv_conf
.valid_handle_regex
);
5190 if (nickserv_conf
.valid_nick_regex_set
)
5191 regfree(&nickserv_conf
.valid_nick_regex
);
5194 void handle_loc_auth_oper(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
)) {
5195 if (!*nickserv_conf
.auto_oper
|| !user
->handle_info
)
5198 if (!IsOper(user
)) {
5199 if (*nickserv_conf
.auto_admin
&& user
->handle_info
->opserv_level
>= opserv_conf_admin_level()) {
5200 irc_umode(user
, nickserv_conf
.auto_admin
);
5201 irc_sno(0x1, "%s (%s@%s) is now an IRC Administrator",
5202 user
->nick
, user
->ident
, user
->hostname
);
5203 } else if (*nickserv_conf
.auto_oper
&& user
->handle_info
->opserv_level
) {
5204 irc_umode(user
, nickserv_conf
.auto_oper
);
5205 irc_sno(0x1, "%s (%s@%s) is now an IRC Operator",
5206 user
->nick
, user
->ident
, user
->hostname
);
5212 init_nickserv(const char *nick
)
5214 struct chanNode
*chan
;
5216 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
5217 reg_new_user_func(check_user_nick
, NULL
);
5218 reg_nick_change_func(handle_nick_change
, NULL
);
5219 reg_del_user_func(nickserv_remove_user
, NULL
);
5220 reg_account_func(handle_account
);
5221 reg_auth_func(handle_loc_auth_oper
);
5223 /* set up handle_inverse_flags */
5224 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
5225 for (i
=0; handle_flags
[i
]; i
++) {
5226 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
5227 flag_access_levels
[i
] = 0;
5230 conf_register_reload(nickserv_conf_read
);
5231 nickserv_opt_dict
= dict_new();
5232 nickserv_email_dict
= dict_new();
5234 dict_set_free_keys(nickserv_email_dict
, free
);
5235 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
5237 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
5238 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
5239 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
5240 * a big pain to disable since its nolonger in the config file. ) -Rubin
5242 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
5243 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
5244 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
5245 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
5246 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
5247 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
5248 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
5249 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
5250 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
5251 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
5252 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
5253 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
5254 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
5255 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
5256 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
5257 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
5258 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
5259 nickserv_define_func("MERGE", cmd_merge
, 750, 1, 0);
5260 if (!nickserv_conf
.disable_nicks
) {
5261 /* nick management commands */
5262 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
5263 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
5264 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
5265 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
5266 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
5267 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
5269 if (nickserv_conf
.email_enabled
) {
5270 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
5271 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
5272 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
5273 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
5274 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
5275 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
5277 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
5278 /* ignore commands */
5279 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
5280 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
5281 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
5282 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
5283 /* miscellaneous commands */
5284 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
5285 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
5286 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
5287 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
5288 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
5289 nickserv_define_func("CHECKEMAIL", cmd_checkemail
, 0, 1, 0);
5291 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
5292 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
5293 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
5294 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
5295 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
5296 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
5297 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
5298 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
5299 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
5300 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
5301 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
5302 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
5303 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
5304 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
5305 if (nickserv_conf
.titlehost_suffix
) {
5306 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
5307 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
5309 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
5310 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
5311 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
5312 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
5313 dict_insert(nickserv_opt_dict
, "KARMA", opt_karma
);
5315 nickserv_handle_dict
= dict_new();
5316 dict_set_free_keys(nickserv_handle_dict
, free
);
5317 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
5319 nickserv_id_dict
= dict_new();
5320 dict_set_free_keys(nickserv_id_dict
, free
);
5322 nickserv_nick_dict
= dict_new();
5323 dict_set_free_data(nickserv_nick_dict
, free
);
5325 nickserv_allow_auth_dict
= dict_new();
5327 userList_init(&curr_helpers
);
5330 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
5331 nickserv
= AddLocalUser(nick
, nick
, NULL
, "Nick Services", modes
);
5332 nickserv_service
= service_register(nickserv
);
5334 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
5335 reg_exit_func(nickserv_db_cleanup
);
5336 if(nickserv_conf
.handle_expire_frequency
)
5337 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
5339 if(autojoin_channels
&& nickserv
) {
5340 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
5341 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
5342 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
5346 ldap_do_init(nickserv_conf
);
5349 message_register_table(msgtab
);