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 void **auth_func_list_extra
;
874 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
877 reg_auth_func(auth_func_t func
, void *extra
)
879 if (auth_func_used
== auth_func_size
) {
880 if (auth_func_size
) {
881 auth_func_size
<<= 1;
882 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
883 auth_func_list_extra
= realloc(auth_func_list_extra
, auth_func_size
*sizeof(void*));
886 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
887 auth_func_list_extra
= malloc(auth_func_size
*sizeof(void*));
890 auth_func_list
[auth_func_used
] = func
;
891 auth_func_list_extra
[auth_func_used
++] = extra
;
894 static handle_rename_func_t
*rf_list
;
895 static void **rf_list_extra
;
896 static unsigned int rf_list_size
, rf_list_used
;
899 reg_handle_rename_func(handle_rename_func_t func
, void *extra
)
901 if (rf_list_used
== rf_list_size
) {
904 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
905 rf_list_extra
= realloc(rf_list_extra
, rf_list_size
*sizeof(void*));
908 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
909 rf_list_extra
= malloc(rf_list_size
*sizeof(void*));
912 rf_list
[rf_list_used
] = func
;
913 rf_list_extra
[rf_list_used
++] = extra
;
917 generate_fakehost(struct handle_info
*handle
)
919 struct userNode
*target
;
920 extern const char *hidden_host_suffix
;
921 static char buffer
[HOSTLEN
+1];
925 if (!handle
->fakehost
) {
926 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
931 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
932 else if (style
== 2) {
933 /* Due to the way fakehost is coded theres no way i can
934 get the exact user, so for now ill just take the first
936 for (target
= handle
->users
; target
; target
= target
->next_authed
)
939 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
942 } else if (handle
->fakehost
[0] == '.') {
943 /* A leading dot indicates the stored value is actually a title. */
944 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
947 return handle
->fakehost
;
951 apply_fakehost(struct handle_info
*handle
)
953 struct userNode
*target
;
958 fake
= generate_fakehost(handle
);
959 for (target
= handle
->users
; target
; target
= target
->next_authed
)
960 assign_fakehost(target
, fake
, 1);
963 void send_func_list(struct userNode
*user
)
966 struct handle_info
*old_info
;
968 old_info
= user
->handle_info
;
970 for (n
=0; n
<auth_func_used
; n
++)
971 auth_func_list
[n
](user
, old_info
, auth_func_list_extra
[n
]);
975 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
978 struct handle_info
*old_info
;
980 /* This can happen if somebody uses COOKIE while authed, or if
981 * they re-auth to their current handle (which is silly, but users
983 if (user
->handle_info
== hi
)
986 if (user
->handle_info
) {
987 struct userNode
*other
;
990 userList_remove(&curr_helpers
, user
);
992 /* remove from next_authed linked list */
993 if (user
->handle_info
->users
== user
) {
994 user
->handle_info
->users
= user
->next_authed
;
995 } else if (user
->handle_info
->users
!= NULL
) {
996 for (other
= user
->handle_info
->users
;
997 other
->next_authed
!= user
;
998 other
= other
->next_authed
) ;
999 other
->next_authed
= user
->next_authed
;
1001 /* No users authed to the account - can happen if they get
1002 * killed for authing. */
1004 /* if nobody left on old handle, and they're not an oper, remove !god */
1005 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
1006 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
1007 /* record them as being last seen at this time */
1008 user
->handle_info
->lastseen
= now
;
1009 /* and record their hostmask */
1010 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
1012 old_info
= user
->handle_info
;
1013 user
->handle_info
= hi
;
1014 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1015 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1017 /* Call auth handlers */
1018 if (!GetUserH(user
->nick
))
1022 struct nick_info
*ni
;
1024 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1025 if (nickserv_conf
.warn_clone_auth
) {
1026 struct userNode
*other
;
1027 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1028 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1031 /* Add this auth to users list of current auths */
1032 user
->next_authed
= hi
->users
;
1035 /* Add to helpers list */
1036 if (IsHelper(user
) && !userList_contains(&curr_helpers
, user
))
1037 userList_append(&curr_helpers
, user
);
1039 /* Set the fakehost */
1040 if (hi
->fakehost
|| old_info
)
1044 #ifdef WITH_PROTOCOL_P10
1045 /* Stamp users with their account name. */
1046 char *id
= hi
->handle
;
1048 const char *id
= "???";
1050 /* Mark all the nicks registered to this
1051 * account as registered nicks
1052 * - Why not just this one? -rubin */
1053 if (!nickserv_conf
.disable_nicks
) {
1054 struct nick_info
*ni2
;
1055 for (ni2
= hi
->nicks
; ni2
; ni2
= ni2
->next
) {
1056 if (!irccasecmp(user
->nick
, ni2
->nick
)) {
1057 user
->modes
|= FLAGS_REGNICK
;
1062 /* send the account to the ircd */
1063 StampUser(user
, id
, hi
->registered
);
1066 /* Stop trying to kick this user off their nick */
1067 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1068 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1070 /* We cannot clear the user's account ID, unfortunately. */
1071 user
->next_authed
= NULL
;
1074 /* Call auth handlers */
1075 if (GetUserH(user
->nick
)) {
1076 for (n
=0; n
<auth_func_used
; n
++) {
1077 auth_func_list
[n
](user
, old_info
, auth_func_list_extra
[n
]);
1084 static struct handle_info
*
1085 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1087 struct handle_info
*hi
;
1088 struct nick_info
*ni
;
1089 char crypted
[MD5_CRYPT_LENGTH
];
1091 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1093 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1097 if(strlen(handle
) > 30)
1100 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 30);
1104 if (!is_secure_password(handle
, passwd
, user
))
1107 cryptpass(passwd
, crypted
);
1109 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1111 rc
= ldap_do_add(handle
, (no_auth
? NULL
: crypted
), NULL
);
1112 if(LDAP_SUCCESS
!= rc
&& LDAP_ALREADY_EXISTS
!= rc
) {
1114 send_message(user
, nickserv
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1119 hi
= register_handle(handle
, crypted
, 0);
1120 hi
->masks
= alloc_string_list(1);
1121 hi
->ignores
= alloc_string_list(1);
1123 hi
->language
= lang_C
;
1124 hi
->registered
= now
;
1126 hi
->flags
= HI_DEFAULT_FLAGS
;
1127 if (settee
&& !no_auth
)
1128 set_user_handle_info(settee
, hi
, 1);
1130 if (user
!= settee
) {
1132 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1134 else if (nickserv_conf
.disable_nicks
) {
1136 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1139 else if (user
&& (ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
))) {
1141 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1146 if (is_registerable_nick(user
->nick
)) {
1147 register_nick(user
->nick
, hi
);
1148 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1152 if (settee
&& (user
!= settee
)) {
1154 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1161 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1163 cookie
->hi
->cookie
= cookie
;
1164 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1167 /* Contributed by the great sneep of afternet ;) */
1168 /* Since this gets used in a URL, we want to avoid stuff that confuses
1169 * email clients such as ] and ?. a-z, 0-9 only.
1171 void genpass(char *str
, int len
)
1176 for(i
= 0; i
< len
; i
++)
1180 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1181 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1189 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1191 struct handle_cookie
*cookie
;
1192 char subject
[128], body
[4096], *misc
;
1193 const char *netname
, *fmt
;
1197 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1201 cookie
= calloc(1, sizeof(*cookie
));
1203 cookie
->type
= type
;
1204 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1206 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1207 /* Adding dedicated password gen function for more control -Rubin */
1208 genpass(cookie
->cookie
, 10);
1210 *inttobase64(cookie->cookie, rand(), 5);
1211 *inttobase64(cookie->cookie+5, rand(), 5);
1214 netname
= nickserv_conf
.network_name
;
1217 switch (cookie
->type
) {
1219 hi
->passwd
[0] = 0; /* invalidate password */
1220 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1221 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1222 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1225 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1227 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1229 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1232 case PASSWORD_CHANGE
:
1233 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1234 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1235 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1237 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1239 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1240 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1244 misc
= hi
->email_addr
;
1245 hi
->email_addr
= cookie
->data
;
1246 #ifdef stupid_verify_old_email
1248 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1249 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1250 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1251 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1252 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1253 mail_send(nickserv
, hi
, subject
, body
, 1);
1254 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1255 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1259 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1260 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1261 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1262 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1263 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1264 mail_send(nickserv
, hi
, subject
, body
, 1);
1266 #ifdef stupid_verify_old_email
1269 hi
->email_addr
= misc
;
1272 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1273 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1274 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1275 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1276 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1279 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1283 mail_send(nickserv
, hi
, subject
, body
, first_time
);
1284 nickserv_bake_cookie(cookie
);
1288 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1290 cookie
->hi
->cookie
= NULL
;
1291 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1292 nickserv_free_cookie(cookie
);
1296 nickserv_free_email_addr(void *data
)
1298 handle_info_list_clean(data
);
1303 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1305 struct handle_info_list
*hil
;
1306 /* Remove from old handle_info_list ... */
1307 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1308 handle_info_list_remove(hil
, hi
);
1309 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1310 hi
->email_addr
= NULL
;
1312 /* Add to the new list.. */
1313 if (new_email_addr
) {
1314 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1315 hil
= calloc(1, sizeof(*hil
));
1316 hil
->tag
= strdup(new_email_addr
);
1317 handle_info_list_init(hil
);
1318 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1320 handle_info_list_append(hil
, hi
);
1321 hi
->email_addr
= hil
->tag
;
1325 static NICKSERV_FUNC(cmd_register
)
1328 struct handle_info
*hi
;
1329 const char *email_addr
, *password
;
1330 char syncpass
[MD5_CRYPT_LENGTH
];
1331 int no_auth
, weblink
;
1333 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1334 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1338 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1339 /* Require the first handle registered to belong to someone +o. */
1340 reply("NSMSG_REQUIRE_OPER");
1344 if (user
->handle_info
) {
1345 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1349 if (IsRegistering(user
)) {
1350 reply("NSMSG_ALREADY_REGISTERING");
1354 if (IsStamped(user
)) {
1355 /* Unauthenticated users might still have been stamped
1356 previously and could therefore have a hidden host;
1357 do not allow them to register a new account. */
1358 reply("NSMSG_STAMPED_REGISTER");
1362 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1364 if(nickserv_conf
.force_handles_lowercase
)
1365 irc_strtolower(argv
[1]);
1366 if (!is_valid_handle(argv
[1])) {
1367 reply("NSMSG_BAD_HANDLE", argv
[1]);
1372 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1373 struct handle_info_list
*hil
;
1376 /* Remember email address. */
1377 email_addr
= argv
[3];
1379 /* Check that the email address looks valid.. */
1380 if (!valid_email(email_addr
)) {
1381 reply("NSMSG_BAD_EMAIL_ADDR");
1385 /* .. and that we are allowed to send to it. */
1386 if ((str
= mail_prohibited_address(email_addr
))) {
1387 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1391 /* If we do email verify, make sure we don't spam the address. */
1392 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1394 for (nn
=0; nn
<hil
->used
; nn
++) {
1395 if (hil
->list
[nn
]->cookie
) {
1396 reply("NSMSG_EMAIL_UNACTIVATED");
1400 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1401 reply("NSMSG_EMAIL_OVERUSED");
1414 /* Webregister hack - send URL instead of IRC cookie
1417 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1421 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1423 /* Add any masks they should get. */
1424 if (nickserv_conf
.default_hostmask
) {
1425 string_list_append(hi
->masks
, strdup("*@*"));
1427 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1428 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1429 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1432 /* If they're the first to register, give them level 1000. */
1433 if (dict_size(nickserv_handle_dict
) == 1) {
1434 hi
->opserv_level
= 1000;
1435 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1438 /* Set their email address. */
1441 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1443 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email_addr
)) != LDAP_SUCCESS
) {
1444 /* Falied to update email in ldap, but still
1445 * updated it here.. what should we do? */
1446 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1448 nickserv_set_email_addr(hi
, email_addr
);
1452 nickserv_set_email_addr(hi
, email_addr
);
1455 nickserv_set_email_addr(hi
, email_addr
);
1459 /* If they need to do email verification, tell them. */
1461 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1463 /* Set registering flag.. */
1464 user
->modes
|= FLAGS_REGISTERING
;
1466 if (nickserv_conf
.sync_log
) {
1467 cryptpass(password
, syncpass
);
1469 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1470 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1473 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1476 /* this wont work if email is required .. */
1477 process_adduser_pending(user
);
1482 static NICKSERV_FUNC(cmd_oregister
)
1484 struct userNode
*settee
= NULL
;
1485 struct handle_info
*hi
;
1486 char* account
= NULL
;
1492 NICKSERV_MIN_PARMS(2);
1496 if(nickserv_conf
.force_handles_lowercase
)
1497 irc_strtolower(account
);
1498 if (!is_valid_handle(argv
[1])) {
1499 reply("NSMSG_BAD_HANDLE", argv
[1]);
1502 if (nickserv_conf
.email_required
) {
1503 NICKSERV_MIN_PARMS(3);
1505 if (argc
> 4) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1506 if (strchr(argv
[4], '@'))
1516 if (argc
> 3) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1517 if (strchr(argv
[3], '@'))
1526 /* If they passed a nick, look for that user.. */
1527 if (nick
&& !(settee
= GetUserH(nick
))) {
1528 reply("MSG_NICK_UNKNOWN", argv
[4]);
1531 /* If the setee is already authed, we cant add a 2nd account for them.. */
1532 if (settee
&& settee
->handle_info
) {
1533 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1536 /* If there is no default mask in the conf, and they didn't pass a mask,
1537 * but we did find a user by nick, generate the mask */
1539 if (nickserv_conf
.default_hostmask
)
1542 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1544 reply("NSMSG_REGISTER_BAD_NICKMASK");
1549 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1550 return 0; /* error reply handled by above */
1554 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1556 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email
)) != LDAP_SUCCESS
) {
1557 /* Falied to update email in ldap, but still
1558 * updated it here.. what should we do? */
1559 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1561 nickserv_set_email_addr(hi
, email
);
1565 nickserv_set_email_addr(hi
, email
);
1568 nickserv_set_email_addr(hi
, email
);
1572 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1573 if (mask_canonicalized
)
1574 string_list_append(hi
->masks
, mask_canonicalized
);
1577 if (nickserv_conf
.sync_log
)
1578 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1583 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1586 struct userNode
*target
;
1587 char *new_mask
= strdup(pretty_mask(mask
));
1588 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1589 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1590 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1595 string_list_append(hi
->ignores
, new_mask
);
1596 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1598 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1599 irc_silence(target
, new_mask
, 1);
1604 static NICKSERV_FUNC(cmd_addignore
)
1606 NICKSERV_MIN_PARMS(2);
1608 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1611 static NICKSERV_FUNC(cmd_oaddignore
)
1613 struct handle_info
*hi
;
1615 NICKSERV_MIN_PARMS(3);
1616 if (!(hi
= get_victim_oper(user
, argv
[1])))
1619 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1623 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1626 struct userNode
*target
;
1627 char *pmask
= strdup(pretty_mask(del_mask
));
1628 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1629 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1630 char *old_mask
= hi
->ignores
->list
[i
];
1631 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1632 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1633 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1634 irc_silence(target
, old_mask
, 0);
1641 reply("NSMSG_DELMASK_NOT_FOUND");
1645 static NICKSERV_FUNC(cmd_delignore
)
1647 NICKSERV_MIN_PARMS(2);
1648 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1651 static NICKSERV_FUNC(cmd_odelignore
)
1653 struct handle_info
*hi
;
1654 NICKSERV_MIN_PARMS(3);
1655 if (!(hi
= get_victim_oper(user
, argv
[1])))
1657 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1660 static NICKSERV_FUNC(cmd_handleinfo
)
1663 unsigned int i
, pos
=0, herelen
;
1664 struct userNode
*target
, *next_un
;
1665 struct handle_info
*hi
;
1666 const char *nsmsg_none
;
1669 if (!(hi
= user
->handle_info
)) {
1670 reply("NSMSG_MUST_AUTH");
1673 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1677 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1678 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1680 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1683 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1684 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1686 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1689 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1690 if (HANDLE_FLAGGED(hi
, FROZEN
))
1691 reply("NSMSG_HANDLEINFO_VACATION");
1693 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1694 struct do_not_register
*dnr
;
1695 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1696 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1697 if ((user
->handle_info
->opserv_level
< 900) && !oper_outranks(user
, hi
))
1699 } else if (hi
!= user
->handle_info
) {
1700 reply("NSMSG_HANDLEINFO_END");
1705 reply("NSMSG_HANDLEINFO_KARMA", hi
->karma
);
1707 if (nickserv_conf
.email_enabled
)
1708 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1712 switch (hi
->cookie
->type
) {
1713 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1714 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1715 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1716 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1717 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1723 unsigned long flen
= 1;
1724 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1726 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1727 if (hi
->flags
& 1 << i
)
1728 flags
[flen
++] = handle_flags
[i
];
1730 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1732 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1735 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1736 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1737 || (hi
->opserv_level
> 0)) {
1738 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1741 if (IsHelping(user
) || IsOper(user
))
1746 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1747 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1752 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1754 if (hi
->last_quit_host
[0])
1755 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1757 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1759 if (nickserv_conf
.disable_nicks
) {
1760 /* nicks disabled; don't show anything about registered nicks */
1761 } else if (hi
->nicks
) {
1762 struct nick_info
*ni
, *next_ni
;
1763 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1764 herelen
= strlen(ni
->nick
);
1765 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1767 goto print_nicks_buff
;
1771 memcpy(buff
+pos
, ni
->nick
, herelen
);
1772 pos
+= herelen
; buff
[pos
++] = ' ';
1776 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1781 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1784 if (hi
->masks
->used
) {
1785 for (i
=0; i
< hi
->masks
->used
; i
++) {
1786 herelen
= strlen(hi
->masks
->list
[i
]);
1787 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1789 goto print_mask_buff
;
1791 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1792 pos
+= herelen
; buff
[pos
++] = ' ';
1793 if (i
+1 == hi
->masks
->used
) {
1796 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1801 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1804 if (hi
->ignores
->used
) {
1805 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1806 herelen
= strlen(hi
->ignores
->list
[i
]);
1807 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1809 goto print_ignore_buff
;
1811 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1812 pos
+= herelen
; buff
[pos
++] = ' ';
1813 if (i
+1 == hi
->ignores
->used
) {
1816 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1821 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1825 struct userData
*chan
, *next
;
1828 for (chan
= hi
->channels
; chan
; chan
= next
) {
1829 next
= chan
->u_next
;
1830 name
= chan
->channel
->channel
->name
;
1831 herelen
= strlen(name
);
1832 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1834 goto print_chans_buff
;
1836 if (IsUserSuspended(chan
))
1838 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(chan
->access
), name
);
1842 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1847 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1850 for (target
= hi
->users
; target
; target
= next_un
) {
1851 herelen
= strlen(target
->nick
);
1852 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1854 goto print_cnick_buff
;
1856 next_un
= target
->next_authed
;
1858 memcpy(buff
+pos
, target
->nick
, herelen
);
1859 pos
+= herelen
; buff
[pos
++] = ' ';
1863 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1868 reply("NSMSG_HANDLEINFO_END");
1869 return 1 | ((hi
!= user
->handle_info
) ? CMD_LOG_STAFF
: 0);
1872 static NICKSERV_FUNC(cmd_userinfo
)
1874 struct userNode
*target
;
1876 NICKSERV_MIN_PARMS(2);
1877 if (!(target
= GetUserH(argv
[1]))) {
1878 reply("MSG_NICK_UNKNOWN", argv
[1]);
1881 if (target
->handle_info
)
1882 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1884 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1888 static NICKSERV_FUNC(cmd_nickinfo
)
1890 struct nick_info
*ni
;
1892 NICKSERV_MIN_PARMS(2);
1893 if (!(ni
= get_nick_info(argv
[1]))) {
1894 reply("MSG_NICK_UNKNOWN", argv
[1]);
1897 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1901 static NICKSERV_FUNC(cmd_rename_handle
)
1903 struct handle_info
*hi
;
1904 struct userNode
*uNode
;
1908 NICKSERV_MIN_PARMS(3);
1909 if(nickserv_conf
.force_handles_lowercase
)
1910 irc_strtolower(argv
[2]);
1911 if (!(hi
= get_victim_oper(user
, argv
[1])))
1913 if (!is_valid_handle(argv
[2])) {
1914 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1917 if (get_handle_info(argv
[2])) {
1918 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1921 if(strlen(argv
[2]) > 30)
1923 reply("NMSG_HANDLE_TOLONG", argv
[2], 30);
1927 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1929 if( (rc
= ldap_rename_account(hi
->handle
, argv
[2])) != LDAP_SUCCESS
) {
1930 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1936 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1937 hi
->handle
= strdup(argv
[2]);
1938 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1939 for (nn
=0; nn
<rf_list_used
; nn
++)
1940 rf_list
[nn
](hi
, old_handle
, rf_list_extra
[nn
]);
1942 if (nickserv_conf
.sync_log
) {
1943 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1944 irc_rename(uNode
, hi
->handle
);
1946 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1949 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1950 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1951 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1957 static failpw_func_t
*failpw_func_list
;
1958 static void **failpw_func_list_extra
;
1959 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1962 reg_failpw_func(failpw_func_t func
, void *extra
)
1964 if (failpw_func_used
== failpw_func_size
) {
1965 if (failpw_func_size
) {
1966 failpw_func_size
<<= 1;
1967 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1968 failpw_func_list_extra
= realloc(failpw_func_list_extra
, failpw_func_size
*sizeof(void*));
1970 failpw_func_size
= 8;
1971 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1972 failpw_func_list_extra
= malloc(failpw_func_size
*sizeof(void*));
1975 failpw_func_list
[failpw_func_used
] = func
;
1976 failpw_func_list_extra
[failpw_func_used
++] = extra
;
1980 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1982 * called by nefariouses enhanced AC login-on-connect code
1985 struct handle_info
*loc_auth(char *handle
, char *password
, char *userhost
)
1987 int pw_arg
, used
, maxlogins
;
1990 struct handle_info
*hi
;
1991 struct userNode
*other
;
1993 int ldap_result
= LDAP_SUCCESS
;
1997 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
2001 if(nickserv_conf
.ldap_enable
) {
2002 ldap_result
= ldap_check_auth(handle
, password
);
2003 if(ldap_result
!= LDAP_SUCCESS
) {
2012 if (!checkpass(password
, hi
->passwd
)) {
2017 /* ldap libs are present but we are not using them... */
2018 if( !nickserv_conf
.ldap_enable
) {
2022 if (!checkpass(password
, hi
->passwd
)) {
2026 else if( (!hi
) && ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2027 /* user not found, but authed to ldap successfully..
2028 * create the account.
2033 /* Add a *@* mask */
2034 /* TODO if userhost is not null, build mask based on that. */
2035 if(nickserv_conf
.default_hostmask
)
2038 return NULL
; /* They dont have a *@* mask so they can't loc */
2040 if(!(hi
= nickserv_register(NULL
, NULL
, handle
, password
, 0))) {
2041 return 0; /* couldn't add the user for some reason */
2044 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2046 if(nickserv_conf
.email_required
) {
2051 nickserv_set_email_addr(hi
, email
);
2055 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2056 string_list_append(hi
->masks
, mask_canonicalized
);
2058 if(nickserv_conf
.sync_log
)
2059 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, "@", handle
);
2063 /* Still no account, so just fail out */
2068 /* We don't know the users hostname, or anything because they
2069 * havn't registered yet. So we can only allow LOC if your
2070 * account has *@* as a hostmask.
2072 * UPDATE: New nefarious LOC supports u@h
2082 buf
= strdup(userhost
);
2083 ident
= mysep(&buf
, "@");
2084 realhost
= mysep(&buf
, ":");
2085 ip
= mysep(&buf
, ":");
2086 if(!ip
|| !realhost
|| !ident
) {
2088 return NULL
; /* Invalid AC request, just quit */
2090 uh
= malloc(strlen(userhost
));
2091 ui
= malloc(strlen(userhost
));
2092 sprintf(uh
, "%s@%s", ident
, realhost
);
2093 sprintf(ui
, "%s@%s", ident
, ip
);
2094 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2096 if(match_ircglob(uh
, hi
->masks
->list
[ii
])
2097 || match_ircglob(ui
, hi
->masks
->list
[ii
]))
2109 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2111 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
2121 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2125 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2126 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2127 if (++used
>= maxlogins
) {
2131 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2135 static NICKSERV_FUNC(cmd_auth
)
2137 char *privv
[MAXNUMPARAMS
];
2139 int pw_arg
, used
, maxlogins
;
2140 struct handle_info
*hi
;
2143 struct userNode
*other
;
2145 int ldap_result
= LDAP_OTHER
;
2149 if (user
->handle_info
) {
2150 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2153 if (IsStamped(user
)) {
2154 /* Unauthenticated users might still have been stamped
2155 previously and could therefore have a hidden host;
2156 do not allow them to authenticate. */
2157 reply("NSMSG_STAMPED_AUTH");
2164 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
2165 } else if (argc
== 2) {
2168 if (nickserv_conf
.disable_nicks
) {
2169 hi
= get_handle_info(user
->nick
);
2171 /* try to look up their handle from their nick */
2172 /* TODO: handle ldap auth on nickserv style networks, too */
2173 struct nick_info
*ni
;
2174 ni
= get_nick_info(user
->nick
);
2176 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
2182 handle
= hi
->handle
;
2184 handle
= user
->nick
;
2187 reply("MSG_MISSING_PARAMS", argv
[0]);
2188 svccmd_send_help_brief(user
, nickserv
, cmd
);
2193 if(strchr(argv
[1], '<') || strchr(handle
, '>')) {
2194 reply("NSMSG_NO_ANGLEBRACKETS");
2197 if (!is_valid_handle(handle
)) {
2198 reply("NSMSG_BAD_HANDLE", handle
);
2202 if(nickserv_conf
.ldap_enable
) {
2203 ldap_result
= ldap_check_auth(handle
, passwd
);
2204 /* Get the users email address and update it */
2205 if(ldap_result
== LDAP_SUCCESS
) {
2207 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2209 if(nickserv_conf
.email_required
) {
2210 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc
));
2215 else if(ldap_result
!= LDAP_INVALID_CREDENTIALS
) {
2216 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2224 if(nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2225 /* user not found, but authed to ldap successfully..
2226 * create the account.
2229 if(!(hi
= nickserv_register(user
, NULL
, argv
[1], argv
[2], 0))) {
2230 reply("NSMSG_UNABLE_TO_ADD");
2231 return 0; /* couldn't add the user for some reason */
2233 /* Add a *@* mask */
2234 if(nickserv_conf
.default_hostmask
)
2237 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2240 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2241 string_list_append(hi
->masks
, mask_canonicalized
);
2244 nickserv_set_email_addr(hi
, email
);
2247 if(nickserv_conf
.sync_log
)
2248 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
);
2252 reply("NSMSG_HANDLE_NOT_FOUND");
2258 /* Responses from here on look up the language used by the handle they asked about. */
2259 if (!valid_user_for(user
, hi
)) {
2260 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
2261 send_message_type(4, user
, cmd
->parent
->bot
,
2262 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
2265 send_message_type(4, user
, cmd
->parent
->bot
,
2266 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
2268 argv
[pw_arg
] = "BADMASK";
2272 if( ( nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_INVALID_CREDENTIALS
) ||
2273 ( (!nickserv_conf
.ldap_enable
) && (!checkpass(passwd
, hi
->passwd
)) ) ) {
2275 if (!checkpass(passwd
, hi
->passwd
)) {
2278 send_message_type(4, user
, cmd
->parent
->bot
,
2279 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
2280 argv
[pw_arg
] = "BADPASS";
2281 for (n
=0; n
<failpw_func_used
; n
++)
2282 failpw_func_list
[n
](user
, hi
, failpw_func_list_extra
[n
]);
2283 if (nickserv_conf
.autogag_enabled
) {
2284 if (!user
->auth_policer
.params
) {
2285 user
->auth_policer
.last_req
= now
;
2286 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
2288 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
2290 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
2291 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
2292 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2294 argv
[pw_arg
] = "GAGGED";
2299 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2300 send_message_type(4, user
, cmd
->parent
->bot
,
2301 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2302 argv
[pw_arg
] = "SUSPENDED";
2305 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2306 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2307 if (++used
>= maxlogins
) {
2308 send_message_type(4, user
, cmd
->parent
->bot
,
2309 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2311 argv
[pw_arg
] = "MAXLOGINS";
2316 set_user_handle_info(user
, hi
, 1);
2317 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2318 reply("NSMSG_PLEASE_SET_EMAIL");
2319 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2320 reply("NSMSG_WEAK_PASSWORD");
2321 if (hi
->passwd
[0] != '$')
2322 cryptpass(passwd
, hi
->passwd
);
2324 /* If a channel was waiting for this user to auth,
2325 * finish adding them */
2326 process_adduser_pending(user
);
2328 reply("NSMSG_AUTH_SUCCESS");
2331 /* Set +x if autohide is on */
2332 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2333 irc_umode(user
, "+x");
2335 if(!IsOper(user
)) /* If they arnt already opered.. */
2337 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2338 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2340 if (nickserv_conf
.auto_admin_privs
[0]) {
2341 irc_raw_privs(user
, nickserv_conf
.auto_admin_privs
);
2342 privc
= split_line(strdup(nickserv_conf
.auto_admin_privs
), false, MAXNUMPARAMS
, privv
);
2343 for (i
= 0; i
< privc
; i
++) {
2344 client_modify_priv_by_name(user
, privv
[i
], 1);
2347 irc_umode(user
,nickserv_conf
.auto_admin
);
2348 reply("NSMSG_AUTO_OPER_ADMIN");
2350 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2352 if (nickserv_conf
.auto_oper_privs
[0]) {
2353 irc_raw_privs(user
, nickserv_conf
.auto_oper_privs
);
2354 privc
= split_line(strdup(nickserv_conf
.auto_oper_privs
), false, MAXNUMPARAMS
, privv
);
2355 for (i
= 0; i
< privc
; i
++) {
2356 client_modify_priv_by_name(user
, privv
[i
], 1);
2359 irc_umode(user
,nickserv_conf
.auto_oper
);
2360 reply("NSMSG_AUTO_OPER");
2364 /* Wipe out the pass for the logs */
2366 if (!hi
->masks
->used
) {
2368 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2369 if (irc_in_addr_is_valid(user
->ip
) && irc_pton(&ip
, NULL
, user
->hostname
))
2370 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2373 argv
[pw_arg
] = "****";
2377 static allowauth_func_t
*allowauth_func_list
;
2378 static void **allowauth_func_list_extra
;
2379 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2382 reg_allowauth_func(allowauth_func_t func
, void *extra
)
2384 if (allowauth_func_used
== allowauth_func_size
) {
2385 if (allowauth_func_size
) {
2386 allowauth_func_size
<<= 1;
2387 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2388 allowauth_func_list_extra
= realloc(allowauth_func_list_extra
, allowauth_func_size
*sizeof(void*));
2390 allowauth_func_size
= 8;
2391 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2392 allowauth_func_list_extra
= malloc(allowauth_func_size
*sizeof(void*));
2395 allowauth_func_list
[allowauth_func_used
] = func
;
2396 allowauth_func_list_extra
[allowauth_func_used
++] = extra
;
2399 static NICKSERV_FUNC(cmd_allowauth
)
2401 struct userNode
*target
;
2402 struct handle_info
*hi
;
2405 NICKSERV_MIN_PARMS(2);
2406 if (!(target
= GetUserH(argv
[1]))) {
2407 reply("MSG_NICK_UNKNOWN", argv
[1]);
2410 if (target
->handle_info
) {
2411 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2414 if (IsStamped(target
)) {
2415 /* Unauthenticated users might still have been stamped
2416 previously and could therefore have a hidden host;
2417 do not allow them to authenticate to an account. */
2418 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2423 else if (!(hi
= get_handle_info(argv
[2]))) {
2424 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2428 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2429 reply("MSG_USER_OUTRANKED", hi
->handle
);
2432 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2433 || (hi
->opserv_level
> 0))
2434 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2435 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2438 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2439 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2440 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2441 if (nickserv_conf
.email_enabled
)
2442 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2444 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2445 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2447 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2449 for (n
=0; n
<allowauth_func_used
; n
++)
2450 allowauth_func_list
[n
](user
, target
, hi
, allowauth_func_list_extra
[n
]);
2454 static NICKSERV_FUNC(cmd_authcookie
)
2456 struct handle_info
*hi
;
2458 NICKSERV_MIN_PARMS(2);
2459 if (user
->handle_info
) {
2460 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2463 if (IsStamped(user
)) {
2464 /* Unauthenticated users might still have been stamped
2465 previously and could therefore have a hidden host;
2466 do not allow them to authenticate to an account. */
2467 reply("NSMSG_STAMPED_AUTHCOOKIE");
2470 if (!(hi
= get_handle_info(argv
[1]))) {
2471 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2474 if (!hi
->email_addr
) {
2475 reply("MSG_SET_EMAIL_ADDR");
2478 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2482 static NICKSERV_FUNC(cmd_delcookie
)
2484 struct handle_info
*hi
;
2486 hi
= user
->handle_info
;
2488 reply("NSMSG_NO_COOKIE");
2491 switch (hi
->cookie
->type
) {
2494 reply("NSMSG_MUST_TIME_OUT");
2497 nickserv_eat_cookie(hi
->cookie
);
2498 reply("NSMSG_ATE_COOKIE");
2504 static NICKSERV_FUNC(cmd_odelcookie
)
2506 struct handle_info
*hi
;
2508 NICKSERV_MIN_PARMS(2);
2510 if (!(hi
= get_victim_oper(user
, argv
[1])))
2514 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2518 switch (hi
->cookie
->type
) {
2520 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2522 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2524 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2525 /* Falied to update password in ldap, but still
2526 * updated it here.. what should we do? */
2527 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2532 if (nickserv_conf
.sync_log
)
2533 SyncLog("ACCOUNTACC %s", hi
->handle
);
2535 case PASSWORD_CHANGE
:
2542 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2543 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2547 nickserv_eat_cookie(hi
->cookie
);
2548 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2553 static NICKSERV_FUNC(cmd_resetpass
)
2555 struct handle_info
*hi
;
2556 char crypted
[MD5_CRYPT_LENGTH
];
2559 NICKSERV_MIN_PARMS(3);
2560 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2564 if (user
->handle_info
) {
2565 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2568 if (IsStamped(user
)) {
2569 /* Unauthenticated users might still have been stamped
2570 previously and could therefore have a hidden host;
2571 do not allow them to activate an account. */
2572 reply("NSMSG_STAMPED_RESETPASS");
2575 if (!(hi
= get_handle_info(argv
[1]))) {
2576 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2579 if (!hi
->email_addr
) {
2580 reply("MSG_SET_EMAIL_ADDR");
2583 cryptpass(argv
[2], crypted
);
2585 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2589 static NICKSERV_FUNC(cmd_cookie
)
2591 struct handle_info
*hi
;
2594 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2597 NICKSERV_MIN_PARMS(3);
2598 if (!(hi
= get_handle_info(argv
[1]))) {
2599 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2605 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2606 reply("NSMSG_HANDLE_SUSPENDED");
2611 reply("NSMSG_NO_COOKIE");
2615 /* Check validity of operation before comparing cookie to
2616 * prohibit guessing by authed users. */
2617 if (user
->handle_info
2618 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2619 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2620 reply("NSMSG_CANNOT_COOKIE");
2624 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2625 reply("NSMSG_BAD_COOKIE");
2629 switch (hi
->cookie
->type
) {
2632 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2634 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2635 /* Falied to update email in ldap, but still
2636 * updated it here.. what should we do? */
2637 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2642 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2643 set_user_handle_info(user
, hi
, 1);
2644 reply("NSMSG_HANDLE_ACTIVATED");
2645 if (nickserv_conf
.sync_log
)
2646 SyncLog("ACCOUNTACC %s", hi
->handle
);
2648 case PASSWORD_CHANGE
:
2650 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2652 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2653 /* Falied to update email in ldap, but still
2654 * updated it here.. what should we do? */
2655 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2660 set_user_handle_info(user
, hi
, 1);
2661 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2662 reply("NSMSG_PASSWORD_CHANGED");
2663 if (nickserv_conf
.sync_log
)
2664 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2668 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2670 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2671 /* Falied to update email in ldap, but still
2672 * updated it here.. what should we do? */
2673 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2678 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2680 * This should only happen if an OREGISTER was sent. Require
2681 * email must be enabled! - SiRVulcaN
2683 if (nickserv_conf
.sync_log
)
2684 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2687 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2688 reply("NSMSG_EMAIL_CHANGED");
2689 if (nickserv_conf
.sync_log
)
2690 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2693 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2694 set_user_handle_info(user
, hi
, 1);
2695 nickserv_addmask(user
, hi
, mask
);
2696 reply("NSMSG_AUTH_SUCCESS");
2701 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2702 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2706 nickserv_eat_cookie(hi
->cookie
);
2708 process_adduser_pending(user
);
2713 static NICKSERV_FUNC(cmd_oregnick
) {
2715 struct handle_info
*target
;
2716 struct nick_info
*ni
;
2718 NICKSERV_MIN_PARMS(3);
2719 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2722 if (!is_registerable_nick(nick
)) {
2723 reply("NSMSG_BAD_NICK", nick
);
2726 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2728 reply("NSMSG_NICK_EXISTS", nick
);
2731 register_nick(nick
, target
);
2732 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2736 static NICKSERV_FUNC(cmd_regnick
) {
2738 struct nick_info
*ni
;
2740 if (!is_registerable_nick(user
->nick
)) {
2741 reply("NSMSG_BAD_NICK", user
->nick
);
2744 /* count their nicks, see if it's too many */
2745 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2746 if (n
>= nickserv_conf
.nicks_per_handle
) {
2747 reply("NSMSG_TOO_MANY_NICKS");
2750 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2752 reply("NSMSG_NICK_EXISTS", user
->nick
);
2755 register_nick(user
->nick
, user
->handle_info
);
2756 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2760 static NICKSERV_FUNC(cmd_pass
)
2762 struct handle_info
*hi
;
2763 char *old_pass
, *new_pass
;
2764 char crypted
[MD5_CRYPT_LENGTH
+1];
2769 NICKSERV_MIN_PARMS(3);
2770 hi
= user
->handle_info
;
2774 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2777 if(nickserv_conf
.ldap_enable
) {
2778 ldap_result
= ldap_check_auth(hi
->handle
, old_pass
);
2779 if(ldap_result
!= LDAP_SUCCESS
) {
2780 if(ldap_result
== LDAP_INVALID_CREDENTIALS
)
2781 reply("NSMSG_PASSWORD_INVALID");
2783 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2788 if (!checkpass(old_pass
, hi
->passwd
)) {
2789 argv
[1] = "BADPASS";
2790 reply("NSMSG_PASSWORD_INVALID");
2793 cryptpass(new_pass
, crypted
);
2795 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2797 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
2798 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2803 //cryptpass(new_pass, hi->passwd);
2804 strcpy(hi
->passwd
, crypted
);
2805 if (nickserv_conf
.sync_log
)
2806 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2808 reply("NSMSG_PASS_SUCCESS");
2813 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2816 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2817 for (i
=0; i
<hi
->masks
->used
; i
++) {
2818 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2819 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2824 string_list_append(hi
->masks
, new_mask
);
2825 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2829 static NICKSERV_FUNC(cmd_addmask
)
2832 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2833 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2837 if (!is_gline(argv
[1])) {
2838 reply("NSMSG_MASK_INVALID", argv
[1]);
2841 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2845 static NICKSERV_FUNC(cmd_oaddmask
)
2847 struct handle_info
*hi
;
2849 NICKSERV_MIN_PARMS(3);
2850 if (!(hi
= get_victim_oper(user
, argv
[1])))
2852 return nickserv_addmask(user
, hi
, argv
[2]);
2856 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
, int force
)
2859 for (i
=0; i
<hi
->masks
->used
; i
++) {
2860 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2861 char *old_mask
= hi
->masks
->list
[i
];
2862 if (hi
->masks
->used
== 1 && !force
) {
2863 reply("NSMSG_DELMASK_NOTLAST");
2866 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2867 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2872 reply("NSMSG_DELMASK_NOT_FOUND");
2876 static NICKSERV_FUNC(cmd_delmask
)
2878 NICKSERV_MIN_PARMS(2);
2879 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1], 0);
2882 static NICKSERV_FUNC(cmd_odelmask
)
2884 struct handle_info
*hi
;
2885 NICKSERV_MIN_PARMS(3);
2886 if (!(hi
= get_victim_oper(user
, argv
[1])))
2888 return nickserv_delmask(cmd
, user
, hi
, argv
[2], 1);
2892 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2893 unsigned int nn
, add
= 1, pos
;
2894 unsigned long added
, removed
, flag
;
2896 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2898 case '+': add
= 1; break;
2899 case '-': add
= 0; break;
2901 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2902 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2905 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2906 /* cheesy avoidance of looking up the flag name.. */
2907 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2910 flag
= 1 << (pos
- 1);
2912 added
|= flag
, removed
&= ~flag
;
2914 removed
|= flag
, added
&= ~flag
;
2919 *premoved
= removed
;
2924 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2926 unsigned long before
, after
, added
, removed
;
2927 struct userNode
*uNode
;
2929 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2930 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2932 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2933 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2935 /* Strip helping flag if they're only a support helper and not
2936 * currently in #support. */
2937 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2938 struct channelList
*schannels
;
2940 schannels
= chanserv_support_channels();
2941 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2942 if (find_handle_in_channel(schannels
->list
[ii
], hi
, NULL
))
2944 if (ii
== schannels
->used
)
2945 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2948 if (after
&& !before
) {
2949 /* Add user to current helper list. */
2950 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2951 userList_append(&curr_helpers
, uNode
);
2952 } else if (!after
&& before
) {
2953 /* Remove user from current helper list. */
2954 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2955 userList_remove(&curr_helpers
, uNode
);
2962 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2966 char *set_display
[] = {
2967 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2968 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2969 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2972 reply("NSMSG_SETTING_LIST");
2973 reply("NSMSG_SETTING_LIST_HEADER");
2975 /* Do this so options are presented in a consistent order. */
2976 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2977 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2978 opt(cmd
, user
, hi
, override
, 0, NULL
);
2979 reply("NSMSG_SETTING_LIST_END");
2982 static NICKSERV_FUNC(cmd_set
)
2984 struct handle_info
*hi
;
2987 hi
= user
->handle_info
;
2989 set_list(cmd
, user
, hi
, 0);
2992 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2993 reply("NSMSG_INVALID_OPTION", argv
[1]);
2996 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2999 static NICKSERV_FUNC(cmd_oset
)
3001 struct handle_info
*hi
;
3004 NICKSERV_MIN_PARMS(2);
3006 if (!(hi
= get_victim_oper(user
, argv
[1])))
3010 set_list(cmd
, user
, hi
, 0);
3014 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
3015 reply("NSMSG_INVALID_OPTION", argv
[2]);
3019 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
3022 static OPTION_FUNC(opt_info
)
3026 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
3028 hi
->infoline
= NULL
;
3030 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
3034 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
3035 reply("NSMSG_SET_INFO", info
);
3039 static OPTION_FUNC(opt_width
)
3042 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
3044 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
3045 hi
->screen_width
= MIN_LINE_SIZE
;
3046 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3047 hi
->screen_width
= MAX_LINE_SIZE
;
3049 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
3053 static OPTION_FUNC(opt_tablewidth
)
3056 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
3058 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
3059 hi
->table_width
= MIN_LINE_SIZE
;
3060 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3061 hi
->table_width
= MAX_LINE_SIZE
;
3063 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
3067 static OPTION_FUNC(opt_color
)
3070 if (enabled_string(argv
[1]))
3071 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
3072 else if (disabled_string(argv
[1]))
3073 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
3075 reply("MSG_INVALID_BINARY", argv
[1]);
3080 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
3084 static OPTION_FUNC(opt_privmsg
)
3087 if (enabled_string(argv
[1]))
3088 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
3089 else if (disabled_string(argv
[1]))
3090 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
3092 reply("MSG_INVALID_BINARY", argv
[1]);
3097 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
3101 static OPTION_FUNC(opt_autohide
)
3104 if (enabled_string(argv
[1]))
3105 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
3106 else if (disabled_string(argv
[1]))
3107 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
3109 reply("MSG_INVALID_BINARY", argv
[1]);
3114 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
3118 static OPTION_FUNC(opt_style
)
3123 if (!irccasecmp(argv
[1], "Clean"))
3124 hi
->userlist_style
= HI_STYLE_CLEAN
;
3125 else if (!irccasecmp(argv
[1], "Advanced"))
3126 hi
->userlist_style
= HI_STYLE_ADVANCED
;
3127 else if (!irccasecmp(argv
[1], "Classic"))
3128 hi
->userlist_style
= HI_STYLE_CLASSIC
;
3129 else /* Default to normal */
3130 hi
->userlist_style
= HI_STYLE_NORMAL
;
3131 } /* TODO: give error if unknow style is chosen */
3133 switch (hi
->userlist_style
) {
3134 case HI_STYLE_ADVANCED
:
3137 case HI_STYLE_CLASSIC
:
3140 case HI_STYLE_CLEAN
:
3143 case HI_STYLE_NORMAL
:
3148 reply("NSMSG_SET_STYLE", style
);
3152 static OPTION_FUNC(opt_announcements
)
3157 if (enabled_string(argv
[1]))
3158 hi
->announcements
= 'y';
3159 else if (disabled_string(argv
[1]))
3160 hi
->announcements
= 'n';
3161 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
3162 hi
->announcements
= '?';
3164 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
3169 switch (hi
->announcements
) {
3170 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
3171 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
3172 case '?': choice
= "default"; break;
3173 default: choice
= "unknown"; break;
3175 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
3179 static OPTION_FUNC(opt_password
)
3181 char crypted
[MD5_CRYPT_LENGTH
+1];
3186 reply("NSMSG_USE_CMD_PASS");
3190 cryptpass(argv
[1], crypted
);
3192 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3194 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
3195 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3200 strcpy(hi
->passwd
, crypted
);
3201 if (nickserv_conf
.sync_log
)
3202 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
3204 reply("NSMSG_SET_PASSWORD", "***");
3208 static OPTION_FUNC(opt_flags
)
3211 unsigned int ii
, flen
;
3214 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3219 nickserv_apply_flags(user
, hi
, argv
[1]);
3221 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
3222 if (hi
->flags
& (1 << ii
))
3223 flags
[flen
++] = handle_flags
[ii
];
3226 reply("NSMSG_SET_FLAGS", flags
);
3228 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
3232 static OPTION_FUNC(opt_email
)
3236 if (!valid_email(argv
[1])) {
3237 reply("NSMSG_BAD_EMAIL_ADDR");
3240 if ((str
= mail_prohibited_address(argv
[1]))) {
3241 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
3244 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
3245 reply("NSMSG_EMAIL_SAME");
3247 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
3250 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3252 if((rc
= ldap_do_modify(hi
->handle
, NULL
, argv
[1])) != LDAP_SUCCESS
) {
3253 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3258 nickserv_set_email_addr(hi
, argv
[1]);
3260 nickserv_eat_cookie(hi
->cookie
);
3261 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3264 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3268 static OPTION_FUNC(opt_maxlogins
)
3270 unsigned char maxlogins
;
3272 maxlogins
= strtoul(argv
[1], NULL
, 0);
3273 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
3274 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
3277 hi
->maxlogins
= maxlogins
;
3279 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
3280 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
3284 static OPTION_FUNC(opt_advanced
)
3287 if (enabled_string(argv
[1]))
3288 HANDLE_SET_FLAG(hi
, ADVANCED
);
3289 else if (disabled_string(argv
[1]))
3290 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
3292 reply("MSG_INVALID_BINARY", argv
[1]);
3297 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
3301 static OPTION_FUNC(opt_language
)
3303 struct language
*lang
;
3305 lang
= language_find(argv
[1]);
3306 if (irccasecmp(lang
->name
, argv
[1]))
3307 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
3308 hi
->language
= lang
;
3310 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
3314 static OPTION_FUNC(opt_karma
)
3317 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3322 if (argv
[1][0] == '+' && isdigit(argv
[1][1])) {
3323 hi
->karma
+= strtoul(argv
[1] + 1, NULL
, 10);
3324 } else if (argv
[1][0] == '-' && isdigit(argv
[1][1])) {
3325 hi
->karma
-= strtoul(argv
[1] + 1, NULL
, 10);
3327 send_message(user
, nickserv
, "NSMSG_INVALID_KARMA", argv
[1]);
3331 send_message(user
, nickserv
, "NSMSG_SET_KARMA", hi
->karma
);
3335 /* Called from opserv from cmd_access */
3337 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
3338 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
3340 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
3341 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
3342 && (user
->handle_info
->opserv_level
< 1000))) {
3343 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
3346 if ((user
->handle_info
->opserv_level
< new_level
)
3347 || ((user
->handle_info
->opserv_level
== new_level
)
3348 && (user
->handle_info
->opserv_level
< 1000))) {
3349 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
3352 if (user
->handle_info
== target
) {
3353 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
3357 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_oper_group_dn
) && *(nickserv_conf
.ldap_admin_dn
)) {
3359 if(new_level
> nickserv_conf
.ldap_oper_group_level
)
3360 rc
= ldap_add2group(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3362 rc
= ldap_delfromgroup(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3363 if(rc
!= LDAP_SUCCESS
&& rc
!= LDAP_TYPE_OR_VALUE_EXISTS
&& rc
!= LDAP_NO_SUCH_ATTRIBUTE
) {
3364 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3368 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_field_oslevel
) && *(nickserv_conf
.ldap_admin_dn
)) {
3370 if((rc
= ldap_do_oslevel(target
->handle
, new_level
, target
->opserv_level
)) != LDAP_SUCCESS
) {
3371 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3376 if (target
->opserv_level
== new_level
)
3378 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
3379 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
3380 target
->opserv_level
= new_level
;
3384 static OPTION_FUNC(opt_level
)
3389 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3393 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
3394 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
3398 static OPTION_FUNC(opt_epithet
)
3400 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
3402 struct userNode
*target
, *next_un
;
3405 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3409 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
3413 if ((epithet
[0] == '*') && !epithet
[1])
3416 hi
->epithet
= strdup(epithet
);
3418 for (target
= hi
->users
; target
; target
= next_un
) {
3419 irc_swhois(nickserv
, target
, hi
->epithet
);
3421 next_un
= target
->next_authed
;
3426 reply("NSMSG_SET_EPITHET", hi
->epithet
);
3428 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
3432 static OPTION_FUNC(opt_title
)
3438 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
3440 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3445 if(!strcmp(title
, "*")) {
3447 hi
->fakehost
= NULL
;
3450 if (strchr(title
, '.')) {
3451 reply("NSMSG_TITLE_INVALID");
3454 /* Alphanumeric titles only. */
3455 for(sptr
= title
; *sptr
; sptr
++) {
3456 if(!isalnum(*sptr
) && *sptr
!= '-') {
3457 reply("NSMSG_TITLE_INVALID");
3461 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
3462 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3463 reply("NSMSG_TITLE_TRUNCATED");
3467 hi
->fakehost
= malloc(strlen(title
)+2);
3468 hi
->fakehost
[0] = '.';
3469 strcpy(hi
->fakehost
+1, title
);
3472 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3473 title
= hi
->fakehost
+ 1;
3475 /* If theres no title set then the default title will therefore
3476 be the first part of hidden_host in x3.conf, so for
3477 consistency with opt_fakehost we will print this here.
3478 This isnt actually used in P10, its just handled to keep from crashing... */
3479 char *hs
, *hidden_suffix
, *rest
;
3481 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3482 hidden_suffix
= strdup(hs
);
3484 /* Yes we do this twice */
3485 if((rest
= strchr(hidden_suffix
, '.')))
3488 title
= hidden_suffix
;
3492 /* A lame default if someone configured hidden_host to something lame */
3493 title
= strdup("users");
3494 free(hidden_suffix
);
3500 none
= user_find_message(user
, "MSG_NONE");
3501 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3506 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3510 // check for a dot in the vhost
3511 if(strchr(vhost
, '.') == NULL
) {
3512 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3516 // check for a @ in the vhost
3517 if(strchr(vhost
, '@') != NULL
) {
3518 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3522 // check for denied words, inspired by monk at paki.sex
3523 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3524 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3525 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3530 // check for ircu's HOSTLEN length.
3531 if(strlen(vhost
) >= HOSTLEN
) {
3532 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3536 /* This can be handled by the regex now if desired.
3537 if (vhost[strspn(vhost, "0123456789.")]) {
3538 hostname = vhost + strlen(vhost);
3539 for (depth = 1; depth && (hostname > vhost); depth--) {
3541 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3544 if (*hostname == '.') hostname++; * advance past last dot we saw *
3545 if(strlen(hostname) > 4) {
3546 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3551 /* test either regex or as valid handle */
3552 if (nickserv_conf
.valid_fakehost_regex_set
) {
3553 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3556 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3557 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3559 if(err
== REG_NOMATCH
) {
3560 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3569 static OPTION_FUNC(opt_fakehost
)
3573 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3575 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3580 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3581 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3584 if (!strcmp(fake
, "*")) {
3587 hi
->fakehost
= NULL
;
3590 else if (!check_vhost(argv
[1], user
, cmd
)) {
3591 /* check_vhost takes care of error reply */
3597 hi
->fakehost
= strdup(fake
);
3600 fake
= hi
->fakehost
;
3602 fake
= generate_fakehost(hi
);
3604 /* Tell them we set the host */
3606 fake
= user_find_message(user
, "MSG_NONE");
3607 reply("NSMSG_SET_FAKEHOST", fake
);
3611 static OPTION_FUNC(opt_note
)
3614 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3619 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3624 if ((text
[0] == '*') && !text
[1])
3627 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3632 reply("NSMSG_SET_NOTE", hi
->note
? hi
->note
->note
: user_find_message(user
, "MSG_NONE"));
3636 static NICKSERV_FUNC(cmd_reclaim
)
3638 struct handle_info
*hi
;
3639 struct nick_info
*ni
;
3640 struct userNode
*victim
;
3642 NICKSERV_MIN_PARMS(2);
3643 hi
= user
->handle_info
;
3644 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3646 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3649 if (ni
->owner
!= user
->handle_info
) {
3650 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3653 victim
= GetUserH(ni
->nick
);
3655 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3658 if (victim
== user
) {
3659 reply("NSMSG_NICK_USER_YOU");
3662 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3663 switch (nickserv_conf
.reclaim_action
) {
3664 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3665 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3666 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3667 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3672 static NICKSERV_FUNC(cmd_unregnick
)
3675 struct handle_info
*hi
;
3676 struct nick_info
*ni
;
3678 hi
= user
->handle_info
;
3679 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3680 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3682 reply("NSMSG_UNKNOWN_NICK", nick
);
3685 if (hi
!= ni
->owner
) {
3686 reply("NSMSG_NOT_YOUR_NICK", nick
);
3689 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3694 static NICKSERV_FUNC(cmd_ounregnick
)
3696 struct nick_info
*ni
;
3698 NICKSERV_MIN_PARMS(2);
3699 if (!(ni
= get_nick_info(argv
[1]))) {
3700 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3703 if (!oper_outranks(user
, ni
->owner
))
3705 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3710 static NICKSERV_FUNC(cmd_unregister
)
3712 struct handle_info
*hi
;
3715 NICKSERV_MIN_PARMS(2);
3716 hi
= user
->handle_info
;
3719 if (checkpass(passwd
, hi
->passwd
)) {
3720 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3725 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3726 reply("NSMSG_PASSWORD_INVALID");
3731 static NICKSERV_FUNC(cmd_ounregister
)
3733 struct handle_info
*hi
;
3734 char reason
[MAXLEN
];
3737 NICKSERV_MIN_PARMS(2);
3738 if (!(hi
= get_victim_oper(user
, argv
[1])))
3741 if (HANDLE_FLAGGED(hi
, NODELETE
)) {
3742 reply("NSMSG_UNREGISTER_NODELETE", hi
->handle
);
3746 force
= IsOper(user
) && (argc
> 2) && !irccasecmp(argv
[2], "force");
3748 ((hi
->flags
& nickserv_conf
.ounregister_flags
)
3750 || (hi
->last_quit_host
[0] && ((unsigned)(now
- hi
->lastseen
) < nickserv_conf
.ounregister_inactive
)))) {
3751 reply((IsOper(user
) ? "NSMSG_UNREGISTER_MUST_FORCE" : "NSMSG_UNREGISTER_CANNOT_FORCE"), hi
->handle
);
3754 snprintf(reason
, sizeof(reason
), "%s unregistered account %s.", user
->handle_info
->handle
, hi
->handle
);
3755 global_message(MESSAGE_RECIPIENT_STAFF
, reason
);
3756 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3762 static NICKSERV_FUNC(cmd_status
)
3764 if (nickserv_conf
.disable_nicks
) {
3765 reply("NSMSG_GLOBAL_STATS_NONICK",
3766 dict_size(nickserv_handle_dict
));
3768 if (user
->handle_info
) {
3770 struct nick_info
*ni
;
3771 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3772 reply("NSMSG_HANDLE_STATS", cnt
);
3774 reply("NSMSG_HANDLE_NONE");
3776 reply("NSMSG_GLOBAL_STATS",
3777 dict_size(nickserv_handle_dict
),
3778 dict_size(nickserv_nick_dict
));
3783 static NICKSERV_FUNC(cmd_ghost
)
3785 struct userNode
*target
;
3786 char reason
[MAXLEN
];
3788 NICKSERV_MIN_PARMS(2);
3789 if (!(target
= GetUserH(argv
[1]))) {
3790 reply("MSG_NICK_UNKNOWN", argv
[1]);
3793 if (target
== user
) {
3794 reply("NSMSG_CANNOT_GHOST_SELF");
3797 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3798 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3801 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3802 DelUser(target
, nickserv
, 1, reason
);
3803 reply("NSMSG_GHOST_KILLED", argv
[1]);
3807 static NICKSERV_FUNC(cmd_vacation
)
3809 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3810 reply("NSMSG_ON_VACATION");
3815 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3817 struct handle_info
*hi
;
3820 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3822 saxdb_start_record(ctx
, iter_key(it
), 0);
3823 if (hi
->announcements
!= '?') {
3824 flags
[0] = hi
->announcements
;
3826 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3829 struct handle_cookie
*cookie
= hi
->cookie
;
3832 switch (cookie
->type
) {
3833 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3834 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3835 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3836 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3837 default: type
= NULL
; break;
3840 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3841 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3842 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3844 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3845 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3846 saxdb_end_record(ctx
);
3850 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3852 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3854 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3855 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3856 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3857 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3858 saxdb_end_record(ctx
);
3862 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3866 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3867 if (hi
->flags
& (1 << ii
))
3868 flags
[flen
++] = handle_flags
[ii
];
3870 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3873 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3874 if (hi
->last_quit_host
[0])
3875 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3876 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3878 saxdb_write_sint(ctx
, KEY_KARMA
, hi
->karma
);
3879 if (hi
->masks
->used
)
3880 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3881 if (hi
->ignores
->used
)
3882 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3884 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3886 struct string_list
*slist
;
3887 struct nick_info
*ni
;
3889 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3890 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3891 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3895 if (hi
->opserv_level
)
3896 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3897 if (hi
->language
!= lang_C
)
3898 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3899 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3900 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3901 if (hi
->screen_width
)
3902 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3903 if (hi
->table_width
)
3904 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3905 flags
[0] = hi
->userlist_style
;
3907 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3908 saxdb_end_record(ctx
);
3914 static handle_merge_func_t
*handle_merge_func_list
;
3915 static void **handle_merge_func_list_extra
;
3916 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3919 reg_handle_merge_func(handle_merge_func_t func
, void *extra
)
3921 if (handle_merge_func_used
== handle_merge_func_size
) {
3922 if (handle_merge_func_size
) {
3923 handle_merge_func_size
<<= 1;
3924 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3925 handle_merge_func_list_extra
= realloc(handle_merge_func_list_extra
, handle_merge_func_size
*sizeof(void*));
3927 handle_merge_func_size
= 8;
3928 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3929 handle_merge_func_list_extra
= malloc(handle_merge_func_size
*sizeof(void*));
3932 handle_merge_func_list
[handle_merge_func_used
] = func
;
3933 handle_merge_func_list_extra
[handle_merge_func_used
++] = extra
;
3936 static NICKSERV_FUNC(cmd_merge
)
3938 struct handle_info
*hi_from
, *hi_to
;
3939 struct userNode
*last_user
;
3940 struct userData
*cList
, *cListNext
;
3941 unsigned int ii
, jj
, n
;
3943 NICKSERV_MIN_PARMS(3);
3945 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3947 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3949 if (hi_to
== hi_from
) {
3950 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3954 for (n
=0; n
<handle_merge_func_used
; n
++)
3955 handle_merge_func_list
[n
](user
, hi_to
, hi_from
, handle_merge_func_list_extra
[n
]);
3957 /* Append "from" handle's nicks to "to" handle's nick list. */
3959 struct nick_info
*last_ni
;
3960 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3961 last_ni
->next
= hi_from
->nicks
;
3963 while (hi_from
->nicks
) {
3964 hi_from
->nicks
->owner
= hi_to
;
3965 hi_from
->nicks
= hi_from
->nicks
->next
;
3968 /* Merge the hostmasks. */
3969 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3970 char *mask
= hi_from
->masks
->list
[ii
];
3971 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3972 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3974 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3975 string_list_append(hi_to
->masks
, strdup(mask
));
3978 /* Merge the ignores. */
3979 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3980 char *ignore
= hi_from
->ignores
->list
[ii
];
3981 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3982 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3984 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3985 string_list_append(hi_to
->ignores
, strdup(ignore
));
3988 /* Merge the lists of authed users. */
3990 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3991 last_user
->next_authed
= hi_from
->users
;
3993 hi_to
->users
= hi_from
->users
;
3995 /* Repoint the old "from" handle's users. */
3996 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3997 last_user
->handle_info
= hi_to
;
3999 hi_from
->users
= NULL
;
4001 /* Merge channel userlists. */
4002 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
4003 struct userData
*cList2
;
4004 cListNext
= cList
->u_next
;
4005 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
4006 if (cList
->channel
== cList2
->channel
)
4008 if (cList2
&& (cList2
->access
>= cList
->access
)) {
4009 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
);
4010 /* keep cList2 in hi_to; remove cList from hi_from */
4011 del_channel_user(cList
, 1);
4014 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
);
4015 /* remove the lower-ranking cList2 from hi_to */
4016 del_channel_user(cList2
, 1);
4018 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
4020 /* cList needs to be moved from hi_from to hi_to */
4021 cList
->handle
= hi_to
;
4022 /* Remove from linked list for hi_from */
4023 assert(!cList
->u_prev
);
4024 hi_from
->channels
= cList
->u_next
;
4026 cList
->u_next
->u_prev
= cList
->u_prev
;
4027 /* Add to linked list for hi_to */
4028 cList
->u_prev
= NULL
;
4029 cList
->u_next
= hi_to
->channels
;
4030 if (hi_to
->channels
)
4031 hi_to
->channels
->u_prev
= cList
;
4032 hi_to
->channels
= cList
;
4036 /* Do they get an OpServ level promotion? */
4037 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
4038 hi_to
->opserv_level
= hi_from
->opserv_level
;
4040 /* What about last seen time? */
4041 if (hi_from
->lastseen
> hi_to
->lastseen
)
4042 hi_to
->lastseen
= hi_from
->lastseen
;
4044 /* New karma is the sum of the two original karmas. */
4045 hi_to
->karma
+= hi_from
->karma
;
4047 /* Does a fakehost carry over? (This intentionally doesn't set it
4048 * for users previously attached to hi_to. They'll just have to
4051 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
4052 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
4054 /* Notify of success. */
4055 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
4056 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
4057 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
4059 /* Unregister the "from" handle. */
4060 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
4061 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
4062 * the process isn't completed.
4068 struct nickserv_discrim
{
4069 unsigned long flags_on
, flags_off
;
4070 time_t min_registered
, max_registered
;
4073 int min_level
, max_level
;
4074 int min_karma
, max_karma
;
4075 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
4076 const char *nickmask
;
4077 const char *hostmask
;
4078 const char *handlemask
;
4079 const char *emailmask
;
4081 unsigned int inldap
;
4085 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
4087 struct discrim_apply_info
{
4088 struct nickserv_discrim
*discrim
;
4089 discrim_search_func func
;
4090 struct userNode
*source
;
4091 unsigned int matched
;
4094 static struct nickserv_discrim
*
4095 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
4098 struct nickserv_discrim
*discrim
;
4100 discrim
= malloc(sizeof(*discrim
));
4101 memset(discrim
, 0, sizeof(*discrim
));
4102 discrim
->min_level
= 0;
4103 discrim
->max_level
= INT_MAX
;
4104 discrim
->limit
= 50;
4105 discrim
->min_registered
= 0;
4106 discrim
->max_registered
= INT_MAX
;
4107 discrim
->lastseen
= LONG_MAX
;
4108 discrim
->min_karma
= INT_MIN
;
4109 discrim
->max_karma
= INT_MAX
;
4111 discrim
->inldap
= 2;
4114 for (i
=0; i
<argc
; i
++) {
4115 if (i
== argc
- 1) {
4116 reply("MSG_MISSING_PARAMS", argv
[i
]);
4119 if (!irccasecmp(argv
[i
], "limit")) {
4120 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
4121 } else if (!irccasecmp(argv
[i
], "flags")) {
4122 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
4123 } else if (!irccasecmp(argv
[i
], "registered")) {
4124 const char *cmp
= argv
[++i
];
4125 if (cmp
[0] == '<') {
4126 if (cmp
[1] == '=') {
4127 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
4129 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
4131 } else if (cmp
[0] == '=') {
4132 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
4133 } else if (cmp
[0] == '>') {
4134 if (cmp
[1] == '=') {
4135 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
4137 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
4140 reply("MSG_INVALID_CRITERIA", cmp
);
4142 } else if (!irccasecmp(argv
[i
], "seen")) {
4143 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
4144 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
4145 discrim
->nickmask
= argv
[++i
];
4146 } else if (!irccasecmp(argv
[i
], "hostmask")) {
4148 if (!irccasecmp(argv
[i
], "exact")) {
4149 if (i
== argc
- 1) {
4150 reply("MSG_MISSING_PARAMS", argv
[i
]);
4153 discrim
->hostmask_type
= EXACT
;
4154 } else if (!irccasecmp(argv
[i
], "subset")) {
4155 if (i
== argc
- 1) {
4156 reply("MSG_MISSING_PARAMS", argv
[i
]);
4159 discrim
->hostmask_type
= SUBSET
;
4160 } else if (!irccasecmp(argv
[i
], "superset")) {
4161 if (i
== argc
- 1) {
4162 reply("MSG_MISSING_PARAMS", argv
[i
]);
4165 discrim
->hostmask_type
= SUPERSET
;
4166 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
4167 if (i
== argc
- 1) {
4168 reply("MSG_MISSING_PARAMS", argv
[i
]);
4171 discrim
->hostmask_type
= LASTQUIT
;
4174 discrim
->hostmask_type
= SUPERSET
;
4176 discrim
->hostmask
= argv
[++i
];
4177 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask") || !irccasecmp(argv
[i
], "account")) {
4178 if (!irccasecmp(argv
[++i
], "*")) {
4179 discrim
->handlemask
= 0;
4181 discrim
->handlemask
= argv
[i
];
4183 } else if (!irccasecmp(argv
[i
], "email")) {
4184 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
4185 reply("MSG_NO_SEARCH_ACCESS", "email");
4187 } else if (!irccasecmp(argv
[++i
], "*")) {
4188 discrim
->emailmask
= 0;
4190 discrim
->emailmask
= argv
[i
];
4192 } else if (!irccasecmp(argv
[i
], "access")) {
4193 const char *cmp
= argv
[++i
];
4194 if (cmp
[0] == '<') {
4195 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
4196 if (cmp
[1] == '=') {
4197 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
4199 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
4201 } else if (cmp
[0] == '=') {
4202 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
4203 } else if (cmp
[0] == '>') {
4204 if (cmp
[1] == '=') {
4205 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
4207 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
4210 reply("MSG_INVALID_CRITERIA", cmp
);
4212 } else if (!irccasecmp(argv
[i
], "karma")) {
4213 const char *cmp
= argv
[++i
];
4214 if (cmp
[0] == '<') {
4215 if (cmp
[1] == '=') {
4216 discrim
->max_karma
= strtoul(cmp
+2, NULL
, 0);
4218 discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0) - 1;
4220 } else if (cmp
[0] == '=') {
4221 discrim
->min_karma
= discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0);
4222 } else if (cmp
[0] == '>') {
4223 if (cmp
[1] == '=') {
4224 discrim
->min_karma
= strtoul(cmp
+2, NULL
, 0);
4226 discrim
->min_karma
= strtoul(cmp
+1, NULL
, 0) + 1;
4229 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
4232 } else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[i
], "inldap")) {
4234 if(true_string(argv
[i
])) {
4235 discrim
->inldap
= 1;
4237 else if (false_string(argv
[i
])) {
4238 discrim
->inldap
= 0;
4241 reply("MSG_INVALID_BINARY", argv
[i
]);
4245 reply("MSG_INVALID_CRITERIA", argv
[i
]);
4256 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
4258 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
4259 || (discrim
->flags_off
& hi
->flags
)
4260 || (discrim
->min_registered
> hi
->registered
)
4261 || (discrim
->max_registered
< hi
->registered
)
4262 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
4263 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
4264 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
4265 || (discrim
->min_level
> hi
->opserv_level
)
4266 || (discrim
->max_level
< hi
->opserv_level
)
4267 || (discrim
->min_karma
> hi
->karma
)
4268 || (discrim
->max_karma
< hi
->karma
)
4272 if (discrim
->hostmask
) {
4274 for (i
=0; i
<hi
->masks
->used
; i
++) {
4275 const char *mask
= hi
->masks
->list
[i
];
4276 if ((discrim
->hostmask_type
== SUBSET
)
4277 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
4278 else if ((discrim
->hostmask_type
== EXACT
)
4279 && !irccasecmp(discrim
->hostmask
, mask
)) break;
4280 else if ((discrim
->hostmask_type
== SUPERSET
)
4281 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
4282 else if ((discrim
->hostmask_type
== LASTQUIT
)
4283 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
4285 if (i
==hi
->masks
->used
) return 0;
4287 if (discrim
->nickmask
) {
4288 struct nick_info
*nick
= hi
->nicks
;
4290 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
4293 if (!nick
) return 0;
4296 if(nickserv_conf
.ldap_enable
&& discrim
->inldap
!= 2) {
4298 rc
= ldap_get_user_info(hi
->handle
, NULL
);
4299 if(discrim
->inldap
== 1 && rc
!= LDAP_SUCCESS
)
4301 if(discrim
->inldap
== 0 && rc
== LDAP_SUCCESS
)
4310 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
4312 dict_iterator_t it
, next
;
4313 unsigned int matched
;
4315 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
4316 it
&& (matched
< discrim
->limit
);
4318 next
= iter_next(it
);
4319 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
4320 dsf(source
, iter_data(it
));
4328 search_print_func(struct userNode
*source
, struct handle_info
*match
)
4330 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
4334 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
4339 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
4341 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
4342 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
4347 search_add2ldap_func (struct userNode
*source
, struct handle_info
*match
)
4350 if(match
->email_addr
&& match
->passwd
&& match
->handle
) {
4351 rc
= ldap_do_add(match
->handle
, match
->passwd
, match
->email_addr
);
4352 if(rc
!= LDAP_SUCCESS
) {
4353 send_message(source
, nickserv
, "NSMSG_LDAP_FAIL_ADD", match
->handle
, ldap_err2string(rc
));
4360 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
4362 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
4363 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
4364 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
4365 return hi_b
->opserv_level
- hi_a
->opserv_level
;
4366 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
4370 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
4372 struct handle_info_list hil
;
4373 struct helpfile_table tbl
;
4378 memset(&hil
, 0, sizeof(hil
));
4379 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
4380 struct handle_info
*hi
= iter_data(it
);
4381 if (hi
->opserv_level
)
4382 handle_info_list_append(&hil
, hi
);
4384 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
4385 tbl
.length
= hil
.used
+ 1;
4387 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
4388 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
4389 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4392 for (ii
= 0; ii
< hil
.used
; ) {
4393 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4394 ary
[0] = hil
.list
[ii
]->handle
;
4395 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
4396 tbl
.contents
[++ii
] = ary
;
4398 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4399 /*reply("MSG_MATCH_COUNT", hil.used); */
4400 for (ii
= 0; ii
< hil
.used
; ii
++)
4401 free(tbl
.contents
[ii
]);
4406 static NICKSERV_FUNC(cmd_search
)
4408 struct nickserv_discrim
*discrim
;
4409 discrim_search_func action
;
4410 struct svccmd
*subcmd
;
4411 unsigned int matches
;
4414 NICKSERV_MIN_PARMS(3);
4415 sprintf(buf
, "search %s", argv
[1]);
4416 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
4417 if (!irccasecmp(argv
[1], "print"))
4418 action
= search_print_func
;
4419 else if (!irccasecmp(argv
[1], "count"))
4420 action
= search_count_func
;
4421 else if (!irccasecmp(argv
[1], "unregister"))
4422 action
= search_unregister_func
;
4424 else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[1], "add2ldap"))
4425 action
= search_add2ldap_func
;
4428 reply("NSMSG_INVALID_ACTION", argv
[1]);
4432 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
4435 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
4439 if (action
== search_print_func
)
4440 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4441 else if (action
== search_count_func
)
4442 discrim
->limit
= INT_MAX
;
4444 matches
= nickserv_discrim_search(discrim
, action
, user
);
4447 reply("MSG_MATCH_COUNT", matches
);
4449 reply("MSG_NO_MATCHES");
4455 static MODCMD_FUNC(cmd_checkpass
)
4457 struct handle_info
*hi
;
4459 NICKSERV_MIN_PARMS(3);
4460 if (!(hi
= get_handle_info(argv
[1]))) {
4461 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
4464 if (checkpass(argv
[2], hi
->passwd
))
4465 reply("CHECKPASS_YES");
4467 reply("CHECKPASS_NO");
4472 static MODCMD_FUNC(cmd_checkemail
)
4474 struct handle_info
*hi
;
4476 NICKSERV_MIN_PARMS(3);
4477 if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
4480 if (!hi
->email_addr
)
4481 reply("CHECKEMAIL_NOT_SET");
4482 else if (!irccasecmp(argv
[2], hi
->email_addr
))
4483 reply("CHECKEMAIL_YES");
4485 reply("CHECKEMAIL_NO");
4490 nickserv_db_read_handle(char *handle
, dict_t obj
)
4493 struct string_list
*masks
, *slist
, *ignores
;
4494 struct handle_info
*hi
;
4495 struct userNode
*authed_users
;
4496 struct userData
*channel_list
;
4497 unsigned long int id
;
4500 char *setter
, *note
;
4503 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
4504 id
= str
? strtoul(str
, NULL
, 0) : 0;
4505 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
4507 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
4510 if ((hi
= get_handle_info(handle
))) {
4511 authed_users
= hi
->users
;
4512 channel_list
= hi
->channels
;
4514 hi
->channels
= NULL
;
4515 dict_remove(nickserv_handle_dict
, hi
->handle
);
4517 authed_users
= NULL
;
4518 channel_list
= NULL
;
4520 if(nickserv_conf
.force_handles_lowercase
)
4521 irc_strtolower(handle
);
4522 hi
= register_handle(handle
, str
, id
);
4524 hi
->users
= authed_users
;
4525 while (authed_users
) {
4526 authed_users
->handle_info
= hi
;
4527 authed_users
= authed_users
->next_authed
;
4530 hi
->channels
= channel_list
;
4531 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
4532 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
4533 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
4534 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
4535 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
4536 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
4537 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
4538 hi
->language
= language_find(str
? str
: "C");
4539 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
4540 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
4541 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
4543 hi
->infoline
= strdup(str
);
4544 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
4545 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4546 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
4547 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
4548 str
= database_get_data(obj
, KEY_KARMA
, RECDB_QSTRING
);
4549 hi
->karma
= str
? strtoul(str
, NULL
, 0) : 0;
4550 /* We want to read the nicks even if disable_nicks is set. This is so
4551 * that we don't lose the nick data entirely. */
4552 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
4554 for (ii
=0; ii
<slist
->used
; ii
++)
4555 register_nick(slist
->list
[ii
], hi
);
4557 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
4559 for (ii
=0; str
[ii
]; ii
++)
4560 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
4562 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
4563 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4564 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
4565 hi
->announcements
= str
? str
[0] : '?';
4566 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
4567 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
4568 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
4569 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
4570 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
4572 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
4574 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
4575 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
4577 nickserv_set_email_addr(hi
, str
);
4578 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
4580 hi
->epithet
= strdup(str
);
4581 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
4583 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
4584 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
4585 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4586 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
4587 if (setter
&& date
&& note
)
4589 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
4594 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
4596 hi
->fakehost
= strdup(str
);
4598 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4600 const char *data
, *type
, *expires
, *cookie_str
;
4601 struct handle_cookie
*cookie
;
4603 cookie
= calloc(1, sizeof(*cookie
));
4604 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4605 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4606 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4607 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4608 if (!type
|| !expires
|| !cookie_str
) {
4609 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4612 if (!irccasecmp(type
, KEY_ACTIVATION
))
4613 cookie
->type
= ACTIVATION
;
4614 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4615 cookie
->type
= PASSWORD_CHANGE
;
4616 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4617 cookie
->type
= EMAIL_CHANGE
;
4618 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4619 cookie
->type
= ALLOWAUTH
;
4621 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4624 cookie
->expires
= strtoul(expires
, NULL
, 0);
4625 if (cookie
->expires
< now
)
4628 cookie
->data
= strdup(data
);
4629 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4633 nickserv_bake_cookie(cookie
);
4635 nickserv_free_cookie(cookie
);
4640 nickserv_saxdb_read(dict_t db
) {
4642 struct record_data
*rd
;
4645 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4647 handle
= strdup(iter_key(it
));
4648 nickserv_db_read_handle(handle
, rd
->d
.object
);
4654 static NICKSERV_FUNC(cmd_mergedb
)
4656 struct timeval start
, stop
;
4659 NICKSERV_MIN_PARMS(2);
4660 gettimeofday(&start
, NULL
);
4661 if (!(db
= parse_database(argv
[1]))) {
4662 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4665 nickserv_saxdb_read(db
);
4667 gettimeofday(&stop
, NULL
);
4668 stop
.tv_sec
-= start
.tv_sec
;
4669 stop
.tv_usec
-= start
.tv_usec
;
4670 if (stop
.tv_usec
< 0) {
4672 stop
.tv_usec
+= 1000000;
4674 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4679 expire_handles(UNUSED_ARG(void *data
))
4681 dict_iterator_t it
, next
;
4683 struct handle_info
*hi
;
4685 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4686 next
= iter_next(it
);
4688 if ((hi
->opserv_level
> 0)
4690 || HANDLE_FLAGGED(hi
, FROZEN
)
4691 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4694 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4695 if ((now
- hi
->lastseen
) > expiry
) {
4696 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4697 nickserv_unregister_handle(hi
, NULL
, NULL
);
4701 if (nickserv_conf
.handle_expire_frequency
)
4702 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4706 nickserv_load_dict(const char *fname
)
4710 if (!(file
= fopen(fname
, "r"))) {
4711 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4714 while (fgets(line
, sizeof(line
), file
)) {
4717 if (line
[strlen(line
)-1] == '\n')
4718 line
[strlen(line
)-1] = 0;
4719 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4722 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4725 static enum reclaim_action
4726 reclaim_action_from_string(const char *str
) {
4728 return RECLAIM_NONE
;
4729 else if (!irccasecmp(str
, "warn"))
4730 return RECLAIM_WARN
;
4731 else if (!irccasecmp(str
, "svsnick"))
4732 return RECLAIM_SVSNICK
;
4733 else if (!irccasecmp(str
, "kill"))
4734 return RECLAIM_KILL
;
4736 return RECLAIM_NONE
;
4740 nickserv_conf_read(void)
4742 dict_t conf_node
, child
;
4745 struct string_list
*strlist
;
4747 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4748 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4751 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4753 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4754 if (nickserv_conf
.valid_handle_regex_set
)
4755 regfree(&nickserv_conf
.valid_handle_regex
);
4757 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4758 nickserv_conf
.valid_handle_regex_set
= !err
;
4759 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4761 nickserv_conf
.valid_handle_regex_set
= 0;
4763 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4764 if (nickserv_conf
.valid_nick_regex_set
)
4765 regfree(&nickserv_conf
.valid_nick_regex
);
4767 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4768 nickserv_conf
.valid_nick_regex_set
= !err
;
4769 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4771 nickserv_conf
.valid_nick_regex_set
= 0;
4773 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4774 if (nickserv_conf
.valid_fakehost_regex_set
)
4775 regfree(&nickserv_conf
.valid_fakehost_regex
);
4777 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4778 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4779 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4781 nickserv_conf
.valid_fakehost_regex_set
= 0;
4783 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4785 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4786 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4787 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4788 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4789 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4790 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4791 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4792 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4793 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4794 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4795 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4796 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4797 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4798 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4799 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4800 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4801 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4802 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4803 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4804 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4805 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4806 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4807 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4808 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4809 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4811 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4812 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4813 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4815 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4816 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4817 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4819 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4820 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4821 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4822 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4823 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4824 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4825 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4826 str
= database_get_data(conf_node
, KEY_OUNREGISTER_INACTIVE
, RECDB_QSTRING
);
4827 nickserv_conf
.ounregister_inactive
= str
? ParseInterval(str
) : 86400*28;
4828 str
= database_get_data(conf_node
, KEY_OUNREGISTER_FLAGS
, RECDB_QSTRING
);
4831 nickserv_conf
.ounregister_flags
= 0;
4833 unsigned int pos
= handle_inverse_flags
[(unsigned char)*str
];
4836 nickserv_conf
.ounregister_flags
|= 1 << (pos
- 1);
4838 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4839 if (!nickserv_conf
.disable_nicks
) {
4840 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4841 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4842 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4843 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4844 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4845 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4846 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4847 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4849 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4850 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4851 const char *key
= iter_key(it
), *value
;
4855 if (!strncasecmp(key
, "uc_", 3))
4856 flag
= toupper(key
[3]);
4857 else if (!strncasecmp(key
, "lc_", 3))
4858 flag
= tolower(key
[3]);
4862 if ((pos
= handle_inverse_flags
[flag
])) {
4863 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4864 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4867 if (nickserv_conf
.weak_password_dict
)
4868 dict_delete(nickserv_conf
.weak_password_dict
);
4869 nickserv_conf
.weak_password_dict
= dict_new();
4870 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4871 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4872 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4873 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4875 nickserv_load_dict(str
);
4876 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4877 if (nickserv
&& str
)
4878 NickChange(nickserv
, str
, 0);
4879 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4880 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4881 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4882 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4883 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4884 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4885 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4886 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4887 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4888 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4889 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4890 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4891 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4892 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4893 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4894 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4895 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4896 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4897 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4898 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4900 free_string_list(nickserv_conf
.denied_fakehost_words
);
4901 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4903 strlist
= string_list_copy(strlist
);
4905 strlist
= alloc_string_list(4);
4906 string_list_append(strlist
, strdup("sex"));
4907 string_list_append(strlist
, strdup("fuck"));
4909 nickserv_conf
.denied_fakehost_words
= strlist
;
4911 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4912 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4914 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4915 nickserv_conf
.auto_oper
= str
? str
: "";
4917 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4918 nickserv_conf
.auto_admin
= str
? str
: "";
4920 str
= database_get_data(conf_node
, KEY_AUTO_OPER_PRIVS
, RECDB_QSTRING
);
4921 nickserv_conf
.auto_oper_privs
= str
? str
: "";
4923 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN_PRIVS
, RECDB_QSTRING
);
4924 nickserv_conf
.auto_admin_privs
= str
? str
: "";
4926 str
= conf_get_data("server/network", RECDB_QSTRING
);
4927 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4928 if (!nickserv_conf
.auth_policer_params
) {
4929 nickserv_conf
.auth_policer_params
= policer_params_new();
4930 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4931 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4933 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4934 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4935 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4937 str
= database_get_data(conf_node
, KEY_LDAP_ENABLE
, RECDB_QSTRING
);
4938 nickserv_conf
.ldap_enable
= str
? strtoul(str
, NULL
, 0) : 0;
4940 str
= database_get_data(conf_node
, KEY_FORCE_HANDLES_LOWERCASE
, RECDB_QSTRING
);
4941 nickserv_conf
.force_handles_lowercase
= str
? strtol(str
, NULL
, 0) : 0;
4944 if(nickserv_conf
.ldap_enable
> 0) {
4945 /* ldap is enabled but not compiled in - error out */
4946 log_module(MAIN_LOG
, LOG_ERROR
, "ldap is enabled in config, but not compiled in!");
4947 nickserv_conf
.ldap_enable
= 0;
4953 str
= database_get_data(conf_node
, KEY_LDAP_URI
, RECDB_QSTRING
);
4954 nickserv_conf
.ldap_uri
= str
? str
: "";
4956 str
= database_get_data(conf_node
, KEY_LDAP_BASE
, RECDB_QSTRING
);
4957 nickserv_conf
.ldap_base
= str
? str
: "";
4959 str
= database_get_data(conf_node
, KEY_LDAP_DN_FMT
, RECDB_QSTRING
);
4960 nickserv_conf
.ldap_dn_fmt
= str
? str
: "";
4962 str
= database_get_data(conf_node
, KEY_LDAP_VERSION
, RECDB_QSTRING
);
4963 nickserv_conf
.ldap_version
= str
? strtoul(str
, NULL
, 0) : 3;
4965 str
= database_get_data(conf_node
, KEY_LDAP_AUTOCREATE
, RECDB_QSTRING
);
4966 nickserv_conf
.ldap_autocreate
= str
? strtoul(str
, NULL
, 0) : 0;
4968 str
= database_get_data(conf_node
, KEY_LDAP_TIMEOUT
, RECDB_QSTRING
);
4969 nickserv_conf
.ldap_timeout
= str
? strtoul(str
, NULL
, 0) : 5;
4971 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_DN
, RECDB_QSTRING
);
4972 nickserv_conf
.ldap_admin_dn
= str
? str
: "";
4974 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_PASS
, RECDB_QSTRING
);
4975 nickserv_conf
.ldap_admin_pass
= str
? str
: "";
4977 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_ACCOUNT
, RECDB_QSTRING
);
4978 nickserv_conf
.ldap_field_account
= str
? str
: "";
4980 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_PASSWORD
, RECDB_QSTRING
);
4981 nickserv_conf
.ldap_field_password
= str
? str
: "";
4983 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_EMAIL
, RECDB_QSTRING
);
4984 nickserv_conf
.ldap_field_email
= str
? str
: "";
4986 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_OSLEVEL
, RECDB_QSTRING
);
4987 nickserv_conf
.ldap_field_oslevel
= str
? str
: "";
4989 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_DN
, RECDB_QSTRING
);
4990 nickserv_conf
.ldap_oper_group_dn
= str
? str
: "";
4992 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_LEVEL
, RECDB_QSTRING
);
4993 nickserv_conf
.ldap_oper_group_level
= str
? strtoul(str
, NULL
, 0) : 99;
4995 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_GROUP_MEMBER
, RECDB_QSTRING
);
4996 nickserv_conf
.ldap_field_group_member
= str
? str
: "";
4998 free_string_list(nickserv_conf
.ldap_object_classes
);
4999 strlist
= database_get_data(conf_node
, KEY_LDAP_OBJECT_CLASSES
, RECDB_STRING_LIST
);
5001 strlist
= string_list_copy(strlist
);
5003 strlist
= alloc_string_list(4);
5004 string_list_append(strlist
, strdup("top"));
5006 nickserv_conf
.ldap_object_classes
= strlist
;
5013 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
5015 char newnick
[NICKLEN
+1];
5024 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
5025 send_message(user
, nickserv
, "NSMSG_RECLAIM_HOWTO", ni
->owner
->handle
, nickserv
->nick
, self
->name
, ni
->owner
->handle
);
5027 case RECLAIM_SVSNICK
:
5029 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
5030 } while (GetUserH(newnick
));
5031 irc_svsnick(nickserv
, user
, newnick
);
5034 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
5035 DelUser(user
, nickserv
, 1, msg
);
5041 nickserv_reclaim_p(void *data
) {
5042 struct userNode
*user
= data
;
5043 struct nick_info
*ni
= get_nick_info(user
->nick
);
5045 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5049 check_user_nick(struct userNode
*user
, UNUSED_ARG(void *extra
)) {
5050 struct nick_info
*ni
;
5051 user
->modes
&= ~FLAGS_REGNICK
;
5052 if (!(ni
= get_nick_info(user
->nick
)))
5054 if (user
->handle_info
== ni
->owner
) {
5055 user
->modes
|= FLAGS_REGNICK
;
5059 if (nickserv_conf
.warn_nick_owned
)
5060 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
5061 send_message(user
, nickserv
, "NSMSG_RECLAIM_HOWTO", ni
->owner
->handle
, nickserv
->nick
, self
->name
, ni
->owner
->handle
);
5062 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
5064 if (nickserv_conf
.auto_reclaim_delay
)
5065 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
5067 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5073 handle_account(struct userNode
*user
, const char *stamp
)
5075 struct handle_info
*hi
;
5078 #ifdef WITH_PROTOCOL_P10
5079 time_t timestamp
= 0;
5081 colon
= strchr(stamp
, ':');
5082 if(colon
&& colon
[1])
5085 timestamp
= atoi(colon
+1);
5087 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
5088 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
5090 log_module(MAIN_LOG
, LOG_WARNING
, "%s using account %s but timestamp does not match %s is not %s.", user
->nick
, stamp
, ctime(×tamp
),
5091 ctime(&hi
->registered
));
5095 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
5096 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
5100 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
5103 set_user_handle_info(user
, hi
, 0);
5105 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
5110 handle_nick_change(struct userNode
*user
, const char *old_nick
, UNUSED_ARG(void *extra
))
5112 struct handle_info
*hi
;
5114 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
5115 dict_remove(nickserv_allow_auth_dict
, old_nick
);
5116 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
5118 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5119 check_user_nick(user
, NULL
);
5123 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
), UNUSED_ARG(void *extra
))
5125 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
5126 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5127 set_user_handle_info(user
, NULL
, 0);
5130 static struct modcmd
*
5131 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
5133 if (min_level
> 0) {
5135 sprintf(buf
, "%u", min_level
);
5136 if (must_be_qualified
) {
5137 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
5139 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
5141 } else if (min_level
== 0) {
5142 if (must_be_qualified
) {
5143 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5145 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5148 if (must_be_qualified
) {
5149 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
5151 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
5157 nickserv_db_cleanup(void)
5159 unreg_del_user_func(nickserv_remove_user
, NULL
);
5160 userList_clean(&curr_helpers
);
5161 policer_params_delete(nickserv_conf
.auth_policer_params
);
5162 dict_delete(nickserv_handle_dict
);
5163 dict_delete(nickserv_nick_dict
);
5164 dict_delete(nickserv_opt_dict
);
5165 dict_delete(nickserv_allow_auth_dict
);
5166 dict_delete(nickserv_email_dict
);
5167 dict_delete(nickserv_id_dict
);
5168 dict_delete(nickserv_conf
.weak_password_dict
);
5169 free(auth_func_list
);
5170 free(auth_func_list_extra
);
5171 free(unreg_func_list
);
5173 free(rf_list_extra
);
5174 free(allowauth_func_list
);
5175 free(allowauth_func_list_extra
);
5176 free(handle_merge_func_list
);
5177 free(handle_merge_func_list_extra
);
5178 free(failpw_func_list
);
5179 free(failpw_func_list_extra
);
5180 if (nickserv_conf
.valid_handle_regex_set
)
5181 regfree(&nickserv_conf
.valid_handle_regex
);
5182 if (nickserv_conf
.valid_nick_regex_set
)
5183 regfree(&nickserv_conf
.valid_nick_regex
);
5186 void handle_loc_auth_oper(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
), UNUSED_ARG(void *extra
)) {
5187 if (!*nickserv_conf
.auto_oper
|| !user
->handle_info
)
5190 if (!IsOper(user
)) {
5191 if (*nickserv_conf
.auto_admin
&& user
->handle_info
->opserv_level
>= opserv_conf_admin_level()) {
5192 irc_umode(user
, nickserv_conf
.auto_admin
);
5193 irc_sno(0x1, "%s (%s@%s) is now an IRC Administrator",
5194 user
->nick
, user
->ident
, user
->hostname
);
5195 } else if (*nickserv_conf
.auto_oper
&& user
->handle_info
->opserv_level
) {
5196 irc_umode(user
, nickserv_conf
.auto_oper
);
5197 irc_sno(0x1, "%s (%s@%s) is now an IRC Operator",
5198 user
->nick
, user
->ident
, user
->hostname
);
5204 init_nickserv(const char *nick
)
5206 struct chanNode
*chan
;
5208 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
5209 reg_new_user_func(check_user_nick
, NULL
);
5210 reg_nick_change_func(handle_nick_change
, NULL
);
5211 reg_del_user_func(nickserv_remove_user
, NULL
);
5212 reg_account_func(handle_account
);
5213 reg_auth_func(handle_loc_auth_oper
, NULL
);
5215 /* set up handle_inverse_flags */
5216 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
5217 for (i
=0; handle_flags
[i
]; i
++) {
5218 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
5219 flag_access_levels
[i
] = 0;
5222 conf_register_reload(nickserv_conf_read
);
5223 nickserv_opt_dict
= dict_new();
5224 nickserv_email_dict
= dict_new();
5226 dict_set_free_keys(nickserv_email_dict
, free
);
5227 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
5229 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
5230 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
5231 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
5232 * a big pain to disable since its nolonger in the config file. ) -Rubin
5234 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
5235 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
5236 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
5237 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
5238 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
5239 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
5240 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
5241 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
5242 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
5243 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
5244 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
5245 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
5246 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
5247 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
5248 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
5249 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
5250 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
5251 nickserv_define_func("MERGE", cmd_merge
, 750, 1, 0);
5252 if (!nickserv_conf
.disable_nicks
) {
5253 /* nick management commands */
5254 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
5255 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
5256 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
5257 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
5258 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
5259 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
5261 if (nickserv_conf
.email_enabled
) {
5262 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
5263 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
5264 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
5265 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
5266 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
5267 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
5269 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
5270 /* ignore commands */
5271 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
5272 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
5273 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
5274 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
5275 /* miscellaneous commands */
5276 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
5277 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
5278 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
5279 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
5280 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
5281 nickserv_define_func("CHECKEMAIL", cmd_checkemail
, 0, 1, 0);
5283 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
5284 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
5285 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
5286 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
5287 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
5288 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
5289 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
5290 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
5291 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
5292 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
5293 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
5294 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
5295 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
5296 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
5297 if (nickserv_conf
.titlehost_suffix
) {
5298 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
5299 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
5301 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
5302 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
5303 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
5304 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
5305 dict_insert(nickserv_opt_dict
, "KARMA", opt_karma
);
5307 nickserv_handle_dict
= dict_new();
5308 dict_set_free_keys(nickserv_handle_dict
, free
);
5309 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
5311 nickserv_id_dict
= dict_new();
5312 dict_set_free_keys(nickserv_id_dict
, free
);
5314 nickserv_nick_dict
= dict_new();
5315 dict_set_free_data(nickserv_nick_dict
, free
);
5317 nickserv_allow_auth_dict
= dict_new();
5319 userList_init(&curr_helpers
);
5322 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
5323 nickserv
= AddLocalUser(nick
, nick
, NULL
, "Nick Services", modes
);
5324 nickserv_service
= service_register(nickserv
);
5326 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
5327 reg_exit_func(nickserv_db_cleanup
);
5328 if(nickserv_conf
.handle_expire_frequency
)
5329 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
5331 if(autojoin_channels
&& nickserv
) {
5332 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
5333 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
5334 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
5338 ldap_do_init(nickserv_conf
);
5341 message_register_table(msgtab
);