1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
32 #include <tre/regex.h>
38 #define NICKSERV_CONF_NAME "services/nickserv"
40 #define KEY_DISABLE_NICKS "disable_nicks"
41 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
42 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
43 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
44 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
45 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
46 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
47 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
48 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
49 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
50 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
51 #define KEY_VALID_FAKEHOST_REGEX "valid_fakehost_regex"
52 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
53 #define KEY_MODOPER_LEVEL "modoper_level"
54 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
55 #define KEY_SET_TITLE_LEVEL "set_title_level"
56 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
57 #define KEY_DENIED_FAKEHOST_WORDS "denied_fakehost_words"
58 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
59 #define KEY_AUTO_OPER "auto_oper"
60 #define KEY_AUTO_ADMIN "auto_admin"
61 #define KEY_AUTO_OPER_PRIVS "auto_oper_privs"
62 #define KEY_AUTO_ADMIN_PRIVS "auto_admin_privs"
63 #define KEY_FLAG_LEVELS "flag_levels"
64 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
65 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
66 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
67 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
68 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
69 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
70 #define KEY_DICT_FILE "dict_file"
71 #define KEY_NICK "nick"
72 #define KEY_LANGUAGE "language"
73 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
74 #define KEY_AUTOGAG_DURATION "autogag_duration"
75 #define KEY_AUTH_POLICER "auth_policer"
76 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
77 #define KEY_EMAIL_ENABLED "email_enabled"
78 #define KEY_EMAIL_REQUIRED "email_required"
79 #define KEY_SYNC_LOG "sync_log"
80 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
81 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
82 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
83 #define KEY_DEFAULT_STYLE "default_style"
84 #define KEY_OUNREGISTER_INACTIVE "ounregister_inactive"
85 #define KEY_OUNREGISTER_FLAGS "ounregister_flags"
88 #define KEY_PASSWD "passwd"
89 #define KEY_NICKS "nicks"
90 #define KEY_MASKS "masks"
91 #define KEY_IGNORES "ignores"
92 #define KEY_OPSERV_LEVEL "opserv_level"
93 #define KEY_FLAGS "flags"
94 #define KEY_REGISTER_ON "register"
95 #define KEY_LAST_SEEN "lastseen"
96 #define KEY_INFO "info"
97 #define KEY_USERLIST_STYLE "user_style"
98 #define KEY_SCREEN_WIDTH "screen_width"
99 #define KEY_LAST_AUTHED_HOST "last_authed_host"
100 #define KEY_LAST_QUIT_HOST "last_quit_host"
101 #define KEY_EMAIL_ADDR "email_addr"
102 #define KEY_COOKIE "cookie"
103 #define KEY_COOKIE_DATA "data"
104 #define KEY_COOKIE_TYPE "type"
105 #define KEY_COOKIE_EXPIRES "expires"
106 #define KEY_ACTIVATION "activation"
107 #define KEY_PASSWORD_CHANGE "password change"
108 #define KEY_EMAIL_CHANGE "email change"
109 #define KEY_ALLOWAUTH "allowauth"
110 #define KEY_EPITHET "epithet"
111 #define KEY_TABLE_WIDTH "table_width"
112 #define KEY_ANNOUNCEMENTS "announcements"
113 #define KEY_MAXLOGINS "maxlogins"
114 #define KEY_FAKEHOST "fakehost"
115 #define KEY_NOTE_NOTE "note"
116 #define KEY_NOTE_SETTER "setter"
117 #define KEY_NOTE_DATE "date"
118 #define KEY_KARMA "karma"
119 #define KEY_FORCE_HANDLES_LOWERCASE "force_handles_lowercase"
121 #define KEY_LDAP_ENABLE "ldap_enable"
124 #define KEY_LDAP_URI "ldap_uri"
125 #define KEY_LDAP_BASE "ldap_base"
126 #define KEY_LDAP_DN_FMT "ldap_dn_fmt"
127 #define KEY_LDAP_VERSION "ldap_version"
128 #define KEY_LDAP_AUTOCREATE "ldap_autocreate"
129 #define KEY_LDAP_ADMIN_DN "ldap_admin_dn"
130 #define KEY_LDAP_ADMIN_PASS "ldap_admin_pass"
131 #define KEY_LDAP_FIELD_ACCOUNT "ldap_field_account"
132 #define KEY_LDAP_FIELD_PASSWORD "ldap_field_password"
133 #define KEY_LDAP_FIELD_EMAIL "ldap_field_email"
134 #define KEY_LDAP_FIELD_OSLEVEL "ldap_field_oslevel"
135 #define KEY_LDAP_OBJECT_CLASSES "ldap_object_classes"
136 #define KEY_LDAP_OPER_GROUP_DN "ldap_oper_group_dn"
137 #define KEY_LDAP_OPER_GROUP_LEVEL "ldap_oper_group_level"
138 #define KEY_LDAP_FIELD_GROUP_MEMBER "ldap_field_group_member"
139 #define KEY_LDAP_TIMEOUT "ldap_timeout"
142 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
144 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
145 #define OPTION_FUNC(NAME) int NAME(UNUSED_ARG(struct svccmd *cmd), struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
146 typedef OPTION_FUNC(option_func_t
);
148 DEFINE_LIST(handle_info_list
, struct handle_info
*)
150 #define NICKSERV_MIN_PARMS(N) do { \
152 reply("MSG_MISSING_PARAMS", argv[0]); \
153 svccmd_send_help_brief(user, nickserv, cmd); \
157 struct userNode
*nickserv
;
158 struct userList curr_helpers
;
159 const char *handle_flags
= HANDLE_FLAGS
;
161 extern struct string_list
*autojoin_channels
;
162 static struct module *nickserv_module
;
163 static struct service
*nickserv_service
;
164 static struct log_type
*NS_LOG
;
165 dict_t nickserv_handle_dict
; /* contains struct handle_info* */
166 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
167 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
168 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
169 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
170 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
171 static char handle_inverse_flags
[256];
172 static unsigned int flag_access_levels
[32];
173 static const struct message_entry msgtab
[] = {
174 { "NSMSG_NO_ANGLEBRACKETS", "The < and > in help indicate that that word is a required parameter, but DO NOT actually type them in messages to me." },
175 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
176 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu characters or less."},
177 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
178 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
179 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
180 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
181 { "NSMSG_LDAP_FAIL", "There was a problem in contacting the account server (ldap): %s. Please try again later." },
182 { "NSMSG_LDAP_FAIL_ADD", "There was a problem in adding account %s to ldap: %s." },
183 { "NSMSG_LDAP_FAIL_SEND_EMAIL", "There was a problem in storing your email address in the account server (ldap): %s. Please try again later." },
184 { "NSMSG_LDAP_FAIL_GET_EMAIL", "There was a problem in retrieving your email address from the account server (ldap): %s. Please try again later." },
185 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
186 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
187 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
188 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
189 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
190 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
191 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
192 { "NSMSG_USE_COOKIE_REGISTER", "To activate your account, you must check your email for the \"cookie\" that has been mailed to it. When you have it, use the $bcookie$b command to complete registration." },
193 { "NSMSG_USE_COOKIE_RESETPASS", "A cookie has been mailed to your account's email address. You must check your email and use the $bcookie$b command to confirm the password change." },
194 { "NSMSG_USE_COOKIE_EMAIL_1", "A cookie has been mailed to the new address you requested. To finish setting your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
195 { "NSMSG_USE_COOKIE_EMAIL_2", "A cookie has been generated, and half mailed to each your old and new addresses. To finish changing your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
196 { "NSMSG_USE_COOKIE_AUTH", "A cookie has been generated and sent to your email address. Once you have checked your email and received the cookie, auth using the $bcookie$b command." },
197 { "NSMSG_COOKIE_LIVE", "Account $b%s$b already has a cookie active. Please either finish using that cookie, wait for it to expire, or auth to the account and use the $bdelcookie$b command." },
198 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
199 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
200 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
201 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
202 { "NSMSG_BAD_COOKIE", "That cookie is not the right one. Please make sure you are copying it EXACTLY from the email; it is case-sensitive, so $bABC$b is different from $babc$b." },
203 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
204 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
205 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
206 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
207 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
208 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
209 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
210 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
211 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
212 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
213 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
214 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
215 { "NSMSG_REGISTER_BAD_NICKMASK", "You must provide a hostmask, or online nick to generate one automatically. (or set a default hostmask in the config such as *@*)." },
216 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
217 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
218 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
219 { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%1$s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %1$s)" },
220 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
221 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
222 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
223 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
224 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
225 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
226 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
227 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
228 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
229 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
230 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
231 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
232 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
233 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
234 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
235 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
236 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
237 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
238 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
239 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
240 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
241 { "NSMSG_HANDLEINFO_KARMA", "Karma: %d" },
242 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
243 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
244 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
245 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
246 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
247 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
248 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
249 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
250 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
251 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
252 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
253 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
254 { "NSMSG_INVALID_KARMA", "$b%s$b is not a valid karma modifier." },
255 { "NSMSG_SET_KARMA", "$bKARMA: $b%d$b" },
256 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
257 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
258 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
259 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
260 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
261 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
262 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
263 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
264 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
265 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
266 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
267 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
268 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
269 { "NSMSG_WEAK_PASSWORD", "WARNING: You are using a password that is considered weak (easy to guess). It is STRONGLY recommended you change it (now, if not sooner) by typing \"/msg $S@$s PASS oldpass newpass\" (with your current password and a new password)." },
270 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
271 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
272 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
273 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
274 { "NSMSG_AUTH_ALLOWED_MSG", "You may now authenticate to account $b%s$b by typing $b/msg $N@$s auth %s password$b (using your password). If you will be using this computer regularly, please type $b/msg $N addmask$b (AFTER you auth) to permanently add your hostmask." },
275 { "NSMSG_AUTH_ALLOWED_EMAIL", "You may also (after you auth) type $b/msg $N set email user@your.isp$b to set an email address. This will let you use the $bauthcookie$b command to be authenticated in the future." },
276 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
277 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
278 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
279 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
280 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
281 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
282 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
283 { "NSMSG_PASS_SUCCESS", "Password changed." },
284 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
285 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
286 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
287 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
288 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
289 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
290 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
291 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
292 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
293 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
294 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
295 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
296 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
297 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
298 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
299 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
300 { "NSMSG_UNREGISTER_MUST_FORCE", "Account $b%s$b is not inactive or has special flags set; use FORCE to unregister it." },
301 { "NSMSG_UNREGISTER_CANNOT_FORCE", "Account $b%s$b is not inactive or has special flags set; have an IRCOp use FORCE to unregister it." },
302 { "NSMSG_UNREGISTER_NODELETE", "Account $b%s$b is protected from unregistration." },
303 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
304 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
305 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
306 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
307 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
308 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
309 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
310 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
311 { "NSMSG_NO_ACCESS", "Access denied." },
312 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
313 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
314 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
315 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
316 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
317 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
318 { "NSMSG_BAD_HANDLE", "Account $b%s$b is not allowed because it is reserved, is too long, or contains invalid characters." },
319 { "NSMSG_BAD_NICK", "Nickname $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
320 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
321 { "NSMSG_FAIL_RENAME", "Account $b%s$b not renamed to $b%s$b because it is in use by a network services, or contains invalid characters." },
322 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
323 { "NSMSG_SEARCH_MATCH", "Match: %s" },
324 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
325 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
326 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
327 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
328 { "NSMSG_RECLAIM_HOWTO", "To auth to account %s you must use /msg %s@%s AUTH %s <password>" },
329 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
330 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
331 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
332 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
333 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
334 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
335 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
336 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
337 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
338 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
339 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
340 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
341 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
342 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
343 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
344 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
345 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
346 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
347 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
348 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
349 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
350 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
351 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
352 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
353 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
354 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
355 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
356 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
357 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
358 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
360 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
361 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
363 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
364 { "NSEMAIL_ACTIVATION_BODY",
365 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
367 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
368 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
369 "This command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n"
370 "/msg %3$s@%4$s AUTH %5$s your-password\n"
371 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
372 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
374 "If you did NOT request this account, you do not need to do anything.\n"
375 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
376 { "NSEMAIL_ACTIVATION_BODY_WEB",
377 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
379 "To verify your email address and complete the account registration, visit the following URL:\n"
380 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
382 "If you did NOT request this account, you do not need to do anything.\n"
383 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
384 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
385 { "NSEMAIL_PASSWORD_CHANGE_BODY",
386 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
387 "To complete the password change, log on to %1$s and type the following command:\n"
388 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
389 "If you did NOT request your password to be changed, you do not need to do anything.\n"
390 "Please contact the %1$s staff if you have questions." },
391 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
392 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
393 "To complete the password change, click the following URL:\n"
394 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
395 "If you did NOT request your password to be changed, you do not need to do anything.\n"
396 "Please contact the %1$s staff if you have questions." },
397 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
398 #ifdef stupid_verify_old_email
399 { "NSEMAIL_EMAIL_CHANGE_BODY_NEW", "This email has been sent to verify that your email address belongs to the same person as account %5$s on %1$s. The SECOND HALF of your cookie is %2$.*6$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s ?????%2$.*6$s\n(Replace the ????? with the FIRST HALF of the cookie, as sent to your OLD email address.)\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
400 { "NSEMAIL_EMAIL_CHANGE_BODY_OLD", "This email has been sent to verify that you want to change your email for account %5$s on %1$s from this address to %7$s. The FIRST HALF of your cookie is %2$.*6$s\nTo verify your new address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$.*6$s?????\n(Replace the ????? with the SECOND HALF of the cookie, as sent to your NEW email address.)\nIf you did NOT request this change of email address, you do not need to do anything. Please contact the %1$s staff if you have questions." },
402 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
403 { "NSEMAIL_EMAIL_VERIFY_BODY", "This email has been sent to verify that this address belongs to the same person as %5$s on %1$s. Your cookie is %2$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
404 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
405 { "NSEMAIL_ALLOWAUTH_BODY", "This email has been sent to let you authenticate (auth) to account %5$s on %1$s. Your cookie is %2$s.\nTo auth to that account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this authorization, you do not need to do anything. Please contact the %1$s staff if you have questions." },
406 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
407 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
408 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
409 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
410 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
411 { "NSMSG_NOT_VALID_FAKEHOST_REGEX", "$b%s$b is not allowed by the admin, consult the valid vhost regex pattern in the config file under nickserv/valid_fakehost_regex." },
412 { "CHECKPASS_YES", "Yes." },
413 { "CHECKPASS_NO", "No." },
414 { "CHECKEMAIL_NOT_SET", "No email set." },
415 { "CHECKEMAIL_YES", "Yes." },
416 { "CHECKEMAIL_NO", "No." },
417 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
421 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
422 static void nickserv_reclaim_p(void *data
);
423 static int nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
);
425 struct nickserv_config nickserv_conf
;
427 /* We have 2^32 unique account IDs to use. */
428 unsigned long int highest_id
= 0;
431 canonicalize_hostmask(char *mask
)
433 char *out
= mask
, *temp
;
434 if ((temp
= strchr(mask
, '!'))) {
436 while (*temp
) *out
++ = *temp
++;
442 static struct handle_note
*
443 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
445 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
447 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
449 memcpy(note
->note
, text
, strlen(text
));
453 static struct handle_info
*
454 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
456 struct handle_info
*hi
;
458 hi
= calloc(1, sizeof(*hi
));
459 hi
->userlist_style
= nickserv_conf
.default_style
? nickserv_conf
.default_style
: HI_DEFAULT_STYLE
;
460 hi
->announcements
= '?';
461 hi
->handle
= strdup(handle
);
462 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
464 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
470 register_nick(const char *nick
, struct handle_info
*owner
)
472 struct nick_info
*ni
;
473 ni
= malloc(sizeof(struct nick_info
));
474 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
476 ni
->next
= owner
->nicks
;
478 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
482 delete_nick(struct nick_info
*ni
)
484 struct nick_info
*last
, *next
;
485 struct userNode
*user
;
486 /* Check to see if we should mark a user as unregistered. */
487 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
488 user
->modes
&= ~FLAGS_REGNICK
;
491 /* Remove ni from the nick_info linked list. */
492 if (ni
== ni
->owner
->nicks
) {
493 ni
->owner
->nicks
= ni
->next
;
495 last
= ni
->owner
->nicks
;
501 last
->next
= next
->next
;
503 dict_remove(nickserv_nick_dict
, ni
->nick
);
506 static unreg_func_t
*unreg_func_list
;
507 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
510 reg_unreg_func(unreg_func_t func
)
512 if (unreg_func_used
== unreg_func_size
) {
513 if (unreg_func_size
) {
514 unreg_func_size
<<= 1;
515 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
518 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
521 unreg_func_list
[unreg_func_used
++] = func
;
525 nickserv_free_cookie(void *data
)
527 struct handle_cookie
*cookie
= data
;
528 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
529 if (cookie
->data
) free(cookie
->data
);
534 free_handle_info(void *vhi
)
536 struct handle_info
*hi
= vhi
;
538 free_string_list(hi
->masks
);
539 free_string_list(hi
->ignores
);
543 delete_nick(hi
->nicks
);
549 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
550 nickserv_free_cookie(hi
->cookie
);
552 if (hi
->email_addr
) {
553 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
554 handle_info_list_remove(hil
, hi
);
556 dict_remove(nickserv_email_dict
, hi
->email_addr
);
561 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
564 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
567 struct userNode
*uNode
;
570 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
572 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
573 if( (rc
= ldap_delete_account(hi
->handle
)) != LDAP_SUCCESS
) {
575 send_message(notify
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
577 if(rc
!= LDAP_NO_SUCH_OBJECT
)
578 return false; /* if theres noone there to delete, its kinda ok, right ?:) */
583 for (n
=0; n
<unreg_func_used
; n
++)
584 unreg_func_list
[n
](notify
, hi
);
586 if (nickserv_conf
.sync_log
) {
587 uNode
= GetUserH(hi
->users
->nick
);
591 set_user_handle_info(hi
->users
, NULL
, 0);
594 if (nickserv_conf
.disable_nicks
)
595 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
597 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
600 if (nickserv_conf
.sync_log
)
601 SyncLog("UNREGISTER %s", hi
->handle
);
603 dict_remove(nickserv_handle_dict
, hi
->handle
);
608 get_handle_info(const char *handle
)
610 return dict_find(nickserv_handle_dict
, handle
, 0);
614 get_nick_info(const char *nick
)
616 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
620 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
625 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
626 mn
= channel
->members
.list
[nn
];
627 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
634 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
635 if (!user
->handle_info
) {
637 send_message(user
, bot
, "MSG_AUTHENTICATE");
641 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
643 send_message(user
, bot
, "NSMSG_NO_ACCESS");
647 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
649 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
653 if (user
->handle_info
->opserv_level
< min_level
) {
655 send_message(user
, bot
, "NSMSG_NO_ACCESS");
663 is_valid_handle(const char *handle
)
665 struct userNode
*user
;
666 /* cant register a juped nick/service nick as handle, to prevent confusion */
667 user
= GetUserH(handle
);
668 if (user
&& IsLocal(user
))
670 /* check against maximum length */
671 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
673 /* for consistency, only allow account names that could be nicks */
674 if (!is_valid_nick(handle
))
676 /* disallow account names that look like bad words */
677 if (opserv_bad_channel(handle
))
679 /* test either regex or containing all valid chars */
680 if (nickserv_conf
.valid_handle_regex_set
) {
681 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
684 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
685 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
689 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
694 is_registerable_nick(const char *nick
)
696 struct userNode
*user
;
697 /* cant register a juped nick/service nick as nick, to prevent confusion */
698 user
= GetUserH(nick
);
699 if (user
&& IsLocal(user
))
701 /* for consistency, only allow nicks names that could be nicks */
702 if (!is_valid_nick(nick
))
704 /* disallow nicks that look like bad words */
705 if (opserv_bad_channel(nick
))
708 if (strlen(nick
) > NICKLEN
)
710 /* test either regex or as valid handle */
711 if (nickserv_conf
.valid_nick_regex_set
) {
712 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
715 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
716 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
722 /* this has been replaced with one in tools.c
725 is_valid_email_addr(const char *email)
727 return strchr(email, '@') != NULL;
733 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
735 if (hi
->email_addr
) {
736 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
737 return hi
->email_addr
;
747 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
749 struct handle_info
*hi
;
750 struct userNode
*target
;
754 if (!(hi
= get_handle_info(++name
))) {
755 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
760 if (!(target
= GetUserH(name
))) {
761 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
764 if (IsLocal(target
)) {
765 if (IsService(target
))
766 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
768 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
771 if (!(hi
= target
->handle_info
)) {
772 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
780 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
781 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
783 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
784 if ((user
->handle_info
->opserv_level
== 1000)
785 || (user
->handle_info
== hi
)
786 || ((user
->handle_info
->opserv_level
== 0)
787 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
788 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
792 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
797 get_victim_oper(struct userNode
*user
, const char *target
)
799 struct handle_info
*hi
;
800 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
802 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
803 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
806 return oper_outranks(user
, hi
) ? hi
: NULL
;
810 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
814 /* If no hostmasks on the account, allow it. */
815 if (!hi
->masks
->used
)
817 /* If any hostmask matches, allow it. */
818 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
819 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0, 0))
821 /* If they are allowauthed to this account, allow it (removing the aa). */
822 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
823 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
826 /* The user is not allowed to use this account. */
831 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
834 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
838 if (len
< nickserv_conf
.password_min_length
) {
840 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
843 if (!irccasecmp(pass
, handle
)) {
845 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
848 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
851 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
854 for (i
=0; i
<len
; i
++) {
855 if (isdigit(pass
[i
]))
857 if (isupper(pass
[i
]))
859 if (islower(pass
[i
]))
862 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
863 || (cnt_upper
< nickserv_conf
.password_min_upper
)
864 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
866 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
872 static auth_func_t
*auth_func_list
;
873 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
876 reg_auth_func(auth_func_t func
)
878 if (auth_func_used
== auth_func_size
) {
879 if (auth_func_size
) {
880 auth_func_size
<<= 1;
881 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
884 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
887 auth_func_list
[auth_func_used
++] = func
;
890 static handle_rename_func_t
*rf_list
;
891 static void **rf_list_extra
;
892 static unsigned int rf_list_size
, rf_list_used
;
895 reg_handle_rename_func(handle_rename_func_t func
, void *extra
)
897 if (rf_list_used
== rf_list_size
) {
900 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
901 rf_list_extra
= realloc(rf_list_extra
, rf_list_size
*sizeof(void*));
904 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
905 rf_list_extra
= malloc(rf_list_size
*sizeof(void*));
908 rf_list
[rf_list_used
] = func
;
909 rf_list_extra
[rf_list_used
++] = extra
;
913 generate_fakehost(struct handle_info
*handle
)
915 struct userNode
*target
;
916 extern const char *hidden_host_suffix
;
917 static char buffer
[HOSTLEN
+1];
921 if (!handle
->fakehost
) {
922 data
= conf_get_data("server/hidden_host_type", RECDB_QSTRING
);
927 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
928 else if (style
== 2) {
929 /* Due to the way fakehost is coded theres no way i can
930 get the exact user, so for now ill just take the first
932 for (target
= handle
->users
; target
; target
= target
->next_authed
)
935 snprintf(buffer
, sizeof(buffer
), "%s", target
->crypthost
);
938 } else if (handle
->fakehost
[0] == '.') {
939 /* A leading dot indicates the stored value is actually a title. */
940 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
943 return handle
->fakehost
;
947 apply_fakehost(struct handle_info
*handle
)
949 struct userNode
*target
;
954 fake
= generate_fakehost(handle
);
955 for (target
= handle
->users
; target
; target
= target
->next_authed
)
956 assign_fakehost(target
, fake
, 1);
959 void send_func_list(struct userNode
*user
)
962 struct handle_info
*old_info
;
964 old_info
= user
->handle_info
;
966 for (n
=0; n
<auth_func_used
; n
++)
967 auth_func_list
[n
](user
, old_info
);
971 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
974 struct handle_info
*old_info
;
976 /* This can happen if somebody uses COOKIE while authed, or if
977 * they re-auth to their current handle (which is silly, but users
979 if (user
->handle_info
== hi
)
982 if (user
->handle_info
) {
983 struct userNode
*other
;
986 userList_remove(&curr_helpers
, user
);
988 /* remove from next_authed linked list */
989 if (user
->handle_info
->users
== user
) {
990 user
->handle_info
->users
= user
->next_authed
;
991 } else if (user
->handle_info
->users
!= NULL
) {
992 for (other
= user
->handle_info
->users
;
993 other
->next_authed
!= user
;
994 other
= other
->next_authed
) ;
995 other
->next_authed
= user
->next_authed
;
997 /* No users authed to the account - can happen if they get
998 * killed for authing. */
1000 /* if nobody left on old handle, and they're not an oper, remove !god */
1001 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
1002 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
1003 /* record them as being last seen at this time */
1004 user
->handle_info
->lastseen
= now
;
1005 /* and record their hostmask */
1006 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
1008 old_info
= user
->handle_info
;
1009 user
->handle_info
= hi
;
1010 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1011 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1013 /* Call auth handlers */
1014 if (!GetUserH(user
->nick
))
1018 struct nick_info
*ni
;
1020 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1021 if (nickserv_conf
.warn_clone_auth
) {
1022 struct userNode
*other
;
1023 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1024 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1027 /* Add this auth to users list of current auths */
1028 user
->next_authed
= hi
->users
;
1031 /* Add to helpers list */
1032 if (IsHelper(user
) && !userList_contains(&curr_helpers
, user
))
1033 userList_append(&curr_helpers
, user
);
1035 /* Set the fakehost */
1036 if (hi
->fakehost
|| old_info
)
1040 #ifdef WITH_PROTOCOL_P10
1041 /* Stamp users with their account name. */
1042 char *id
= hi
->handle
;
1044 const char *id
= "???";
1046 /* Mark all the nicks registered to this
1047 * account as registered nicks
1048 * - Why not just this one? -rubin */
1049 if (!nickserv_conf
.disable_nicks
) {
1050 struct nick_info
*ni2
;
1051 for (ni2
= hi
->nicks
; ni2
; ni2
= ni2
->next
) {
1052 if (!irccasecmp(user
->nick
, ni2
->nick
)) {
1053 user
->modes
|= FLAGS_REGNICK
;
1058 /* send the account to the ircd */
1059 StampUser(user
, id
, hi
->registered
);
1062 /* Stop trying to kick this user off their nick */
1063 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1064 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1066 /* We cannot clear the user's account ID, unfortunately. */
1067 user
->next_authed
= NULL
;
1070 /* Call auth handlers */
1071 if (GetUserH(user
->nick
)) {
1072 for (n
=0; n
<auth_func_used
; n
++) {
1073 auth_func_list
[n
](user
, old_info
);
1080 static struct handle_info
*
1081 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1083 struct handle_info
*hi
;
1084 struct nick_info
*ni
;
1085 char crypted
[MD5_CRYPT_LENGTH
];
1087 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1089 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1093 if(strlen(handle
) > 30)
1096 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 30);
1100 if (!is_secure_password(handle
, passwd
, user
))
1103 cryptpass(passwd
, crypted
);
1105 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1107 rc
= ldap_do_add(handle
, (no_auth
? NULL
: crypted
), NULL
);
1108 if(LDAP_SUCCESS
!= rc
&& LDAP_ALREADY_EXISTS
!= rc
) {
1110 send_message(user
, nickserv
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1115 hi
= register_handle(handle
, crypted
, 0);
1116 hi
->masks
= alloc_string_list(1);
1117 hi
->ignores
= alloc_string_list(1);
1119 hi
->language
= lang_C
;
1120 hi
->registered
= now
;
1122 hi
->flags
= HI_DEFAULT_FLAGS
;
1123 if (settee
&& !no_auth
)
1124 set_user_handle_info(settee
, hi
, 1);
1126 if (user
!= settee
) {
1128 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1130 else if (nickserv_conf
.disable_nicks
) {
1132 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1135 else if (user
&& (ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
))) {
1137 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1142 if (is_registerable_nick(user
->nick
)) {
1143 register_nick(user
->nick
, hi
);
1144 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1148 if (settee
&& (user
!= settee
)) {
1150 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1157 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1159 cookie
->hi
->cookie
= cookie
;
1160 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1163 /* Contributed by the great sneep of afternet ;) */
1164 /* Since this gets used in a URL, we want to avoid stuff that confuses
1165 * email clients such as ] and ?. a-z, 0-9 only.
1167 void genpass(char *str
, int len
)
1172 for(i
= 0; i
< len
; i
++)
1176 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1177 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1185 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1187 struct handle_cookie
*cookie
;
1188 char subject
[128], body
[4096], *misc
;
1189 const char *netname
, *fmt
;
1193 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1197 cookie
= calloc(1, sizeof(*cookie
));
1199 cookie
->type
= type
;
1200 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1202 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1203 /* Adding dedicated password gen function for more control -Rubin */
1204 genpass(cookie
->cookie
, 10);
1206 *inttobase64(cookie->cookie, rand(), 5);
1207 *inttobase64(cookie->cookie+5, rand(), 5);
1210 netname
= nickserv_conf
.network_name
;
1213 switch (cookie
->type
) {
1215 hi
->passwd
[0] = 0; /* invalidate password */
1216 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1217 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1218 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1221 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1223 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1225 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1228 case PASSWORD_CHANGE
:
1229 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1230 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1231 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1233 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1235 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1236 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1240 misc
= hi
->email_addr
;
1241 hi
->email_addr
= cookie
->data
;
1242 #ifdef stupid_verify_old_email
1244 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1245 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1246 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1247 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1248 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1249 mail_send(nickserv
, hi
, subject
, body
, 1);
1250 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1251 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1255 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1256 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1257 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1258 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1259 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1260 mail_send(nickserv
, hi
, subject
, body
, 1);
1262 #ifdef stupid_verify_old_email
1265 hi
->email_addr
= misc
;
1268 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1269 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1270 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1271 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1272 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1275 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1279 mail_send(nickserv
, hi
, subject
, body
, first_time
);
1280 nickserv_bake_cookie(cookie
);
1284 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1286 cookie
->hi
->cookie
= NULL
;
1287 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1288 nickserv_free_cookie(cookie
);
1292 nickserv_free_email_addr(void *data
)
1294 handle_info_list_clean(data
);
1299 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1301 struct handle_info_list
*hil
;
1302 /* Remove from old handle_info_list ... */
1303 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1304 handle_info_list_remove(hil
, hi
);
1305 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1306 hi
->email_addr
= NULL
;
1308 /* Add to the new list.. */
1309 if (new_email_addr
) {
1310 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1311 hil
= calloc(1, sizeof(*hil
));
1312 hil
->tag
= strdup(new_email_addr
);
1313 handle_info_list_init(hil
);
1314 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1316 handle_info_list_append(hil
, hi
);
1317 hi
->email_addr
= hil
->tag
;
1321 static NICKSERV_FUNC(cmd_register
)
1324 struct handle_info
*hi
;
1325 const char *email_addr
, *password
;
1326 char syncpass
[MD5_CRYPT_LENGTH
];
1327 int no_auth
, weblink
;
1329 if (checkDefCon(DEFCON_NO_NEW_NICKS
) && !IsOper(user
)) {
1330 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf
.disable_nicks
? "accounts" : "nicknames");
1334 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1335 /* Require the first handle registered to belong to someone +o. */
1336 reply("NSMSG_REQUIRE_OPER");
1340 if (user
->handle_info
) {
1341 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1345 if (IsRegistering(user
)) {
1346 reply("NSMSG_ALREADY_REGISTERING");
1350 if (IsStamped(user
)) {
1351 /* Unauthenticated users might still have been stamped
1352 previously and could therefore have a hidden host;
1353 do not allow them to register a new account. */
1354 reply("NSMSG_STAMPED_REGISTER");
1358 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1360 if(nickserv_conf
.force_handles_lowercase
)
1361 irc_strtolower(argv
[1]);
1362 if (!is_valid_handle(argv
[1])) {
1363 reply("NSMSG_BAD_HANDLE", argv
[1]);
1368 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1369 struct handle_info_list
*hil
;
1372 /* Remember email address. */
1373 email_addr
= argv
[3];
1375 /* Check that the email address looks valid.. */
1376 if (!valid_email(email_addr
)) {
1377 reply("NSMSG_BAD_EMAIL_ADDR");
1381 /* .. and that we are allowed to send to it. */
1382 if ((str
= mail_prohibited_address(email_addr
))) {
1383 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1387 /* If we do email verify, make sure we don't spam the address. */
1388 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1390 for (nn
=0; nn
<hil
->used
; nn
++) {
1391 if (hil
->list
[nn
]->cookie
) {
1392 reply("NSMSG_EMAIL_UNACTIVATED");
1396 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1397 reply("NSMSG_EMAIL_OVERUSED");
1410 /* Webregister hack - send URL instead of IRC cookie
1413 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1417 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1419 /* Add any masks they should get. */
1420 if (nickserv_conf
.default_hostmask
) {
1421 string_list_append(hi
->masks
, strdup("*@*"));
1423 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1424 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1425 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1428 /* If they're the first to register, give them level 1000. */
1429 if (dict_size(nickserv_handle_dict
) == 1) {
1430 hi
->opserv_level
= 1000;
1431 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1434 /* Set their email address. */
1437 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1439 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email_addr
)) != LDAP_SUCCESS
) {
1440 /* Falied to update email in ldap, but still
1441 * updated it here.. what should we do? */
1442 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1444 nickserv_set_email_addr(hi
, email_addr
);
1448 nickserv_set_email_addr(hi
, email_addr
);
1451 nickserv_set_email_addr(hi
, email_addr
);
1455 /* If they need to do email verification, tell them. */
1457 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1459 /* Set registering flag.. */
1460 user
->modes
|= FLAGS_REGISTERING
;
1462 if (nickserv_conf
.sync_log
) {
1463 cryptpass(password
, syncpass
);
1465 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1466 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1469 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1472 /* this wont work if email is required .. */
1473 process_adduser_pending(user
);
1478 static NICKSERV_FUNC(cmd_oregister
)
1480 struct userNode
*settee
= NULL
;
1481 struct handle_info
*hi
;
1482 char* account
= NULL
;
1488 NICKSERV_MIN_PARMS(2);
1492 if(nickserv_conf
.force_handles_lowercase
)
1493 irc_strtolower(account
);
1494 if (!is_valid_handle(argv
[1])) {
1495 reply("NSMSG_BAD_HANDLE", argv
[1]);
1498 if (nickserv_conf
.email_required
) {
1499 NICKSERV_MIN_PARMS(3);
1501 if (argc
> 4) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1502 if (strchr(argv
[4], '@'))
1512 if (argc
> 3) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1513 if (strchr(argv
[3], '@'))
1522 /* If they passed a nick, look for that user.. */
1523 if (nick
&& !(settee
= GetUserH(nick
))) {
1524 reply("MSG_NICK_UNKNOWN", argv
[4]);
1527 /* If the setee is already authed, we cant add a 2nd account for them.. */
1528 if (settee
&& settee
->handle_info
) {
1529 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1532 /* If there is no default mask in the conf, and they didn't pass a mask,
1533 * but we did find a user by nick, generate the mask */
1535 if (nickserv_conf
.default_hostmask
)
1538 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1540 reply("NSMSG_REGISTER_BAD_NICKMASK");
1545 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1546 return 0; /* error reply handled by above */
1550 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1552 if((rc
= ldap_do_modify(hi
->handle
, NULL
, email
)) != LDAP_SUCCESS
) {
1553 /* Falied to update email in ldap, but still
1554 * updated it here.. what should we do? */
1555 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc
));
1557 nickserv_set_email_addr(hi
, email
);
1561 nickserv_set_email_addr(hi
, email
);
1564 nickserv_set_email_addr(hi
, email
);
1568 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1569 if (mask_canonicalized
)
1570 string_list_append(hi
->masks
, mask_canonicalized
);
1573 if (nickserv_conf
.sync_log
)
1574 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1579 nickserv_ignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1582 struct userNode
*target
;
1583 char *new_mask
= strdup(pretty_mask(mask
));
1584 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1585 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1586 reply("NSMSG_ADDIGNORE_ALREADY", new_mask
);
1591 string_list_append(hi
->ignores
, new_mask
);
1592 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1594 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1595 irc_silence(target
, new_mask
, 1);
1600 static NICKSERV_FUNC(cmd_addignore
)
1602 NICKSERV_MIN_PARMS(2);
1604 return nickserv_ignore(cmd
, user
, user
->handle_info
, argv
[1]);
1607 static NICKSERV_FUNC(cmd_oaddignore
)
1609 struct handle_info
*hi
;
1611 NICKSERV_MIN_PARMS(3);
1612 if (!(hi
= get_victim_oper(user
, argv
[1])))
1615 return nickserv_ignore(cmd
, user
, hi
, argv
[2]);
1619 nickserv_delignore(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1622 struct userNode
*target
;
1623 char *pmask
= strdup(pretty_mask(del_mask
));
1624 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1625 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1626 char *old_mask
= hi
->ignores
->list
[i
];
1627 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1628 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
1629 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1630 irc_silence(target
, old_mask
, 0);
1637 reply("NSMSG_DELMASK_NOT_FOUND");
1641 static NICKSERV_FUNC(cmd_delignore
)
1643 NICKSERV_MIN_PARMS(2);
1644 return nickserv_delignore(cmd
, user
, user
->handle_info
, argv
[1]);
1647 static NICKSERV_FUNC(cmd_odelignore
)
1649 struct handle_info
*hi
;
1650 NICKSERV_MIN_PARMS(3);
1651 if (!(hi
= get_victim_oper(user
, argv
[1])))
1653 return nickserv_delignore(cmd
, user
, hi
, argv
[2]);
1656 static NICKSERV_FUNC(cmd_handleinfo
)
1659 unsigned int i
, pos
=0, herelen
;
1660 struct userNode
*target
, *next_un
;
1661 struct handle_info
*hi
;
1662 const char *nsmsg_none
;
1665 if (!(hi
= user
->handle_info
)) {
1666 reply("NSMSG_MUST_AUTH");
1669 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1673 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1674 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1676 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1679 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1680 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1682 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1685 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1686 if (HANDLE_FLAGGED(hi
, FROZEN
))
1687 reply("NSMSG_HANDLEINFO_VACATION");
1689 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1690 struct do_not_register
*dnr
;
1691 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1692 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1693 if ((user
->handle_info
->opserv_level
< 900) && !oper_outranks(user
, hi
))
1695 } else if (hi
!= user
->handle_info
) {
1696 reply("NSMSG_HANDLEINFO_END");
1701 reply("NSMSG_HANDLEINFO_KARMA", hi
->karma
);
1703 if (nickserv_conf
.email_enabled
)
1704 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1708 switch (hi
->cookie
->type
) {
1709 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1710 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1711 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1712 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1713 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1719 unsigned long flen
= 1;
1720 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1722 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1723 if (hi
->flags
& 1 << i
)
1724 flags
[flen
++] = handle_flags
[i
];
1726 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1728 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1731 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1732 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1733 || (hi
->opserv_level
> 0)) {
1734 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1737 if (IsHelping(user
) || IsOper(user
))
1742 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1743 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1748 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1750 if (hi
->last_quit_host
[0])
1751 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1753 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1755 if (nickserv_conf
.disable_nicks
) {
1756 /* nicks disabled; don't show anything about registered nicks */
1757 } else if (hi
->nicks
) {
1758 struct nick_info
*ni
, *next_ni
;
1759 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1760 herelen
= strlen(ni
->nick
);
1761 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1763 goto print_nicks_buff
;
1767 memcpy(buff
+pos
, ni
->nick
, herelen
);
1768 pos
+= herelen
; buff
[pos
++] = ' ';
1772 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1777 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1780 if (hi
->masks
->used
) {
1781 for (i
=0; i
< hi
->masks
->used
; i
++) {
1782 herelen
= strlen(hi
->masks
->list
[i
]);
1783 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1785 goto print_mask_buff
;
1787 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1788 pos
+= herelen
; buff
[pos
++] = ' ';
1789 if (i
+1 == hi
->masks
->used
) {
1792 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1797 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1800 if (hi
->ignores
->used
) {
1801 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1802 herelen
= strlen(hi
->ignores
->list
[i
]);
1803 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1805 goto print_ignore_buff
;
1807 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1808 pos
+= herelen
; buff
[pos
++] = ' ';
1809 if (i
+1 == hi
->ignores
->used
) {
1812 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1817 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1821 struct userData
*chan
, *next
;
1824 for (chan
= hi
->channels
; chan
; chan
= next
) {
1825 next
= chan
->u_next
;
1826 name
= chan
->channel
->channel
->name
;
1827 herelen
= strlen(name
);
1828 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1830 goto print_chans_buff
;
1832 if (IsUserSuspended(chan
))
1834 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(chan
->access
), name
);
1838 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1843 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1846 for (target
= hi
->users
; target
; target
= next_un
) {
1847 herelen
= strlen(target
->nick
);
1848 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1850 goto print_cnick_buff
;
1852 next_un
= target
->next_authed
;
1854 memcpy(buff
+pos
, target
->nick
, herelen
);
1855 pos
+= herelen
; buff
[pos
++] = ' ';
1859 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1864 reply("NSMSG_HANDLEINFO_END");
1865 return 1 | ((hi
!= user
->handle_info
) ? CMD_LOG_STAFF
: 0);
1868 static NICKSERV_FUNC(cmd_userinfo
)
1870 struct userNode
*target
;
1872 NICKSERV_MIN_PARMS(2);
1873 if (!(target
= GetUserH(argv
[1]))) {
1874 reply("MSG_NICK_UNKNOWN", argv
[1]);
1877 if (target
->handle_info
)
1878 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1880 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1884 static NICKSERV_FUNC(cmd_nickinfo
)
1886 struct nick_info
*ni
;
1888 NICKSERV_MIN_PARMS(2);
1889 if (!(ni
= get_nick_info(argv
[1]))) {
1890 reply("MSG_NICK_UNKNOWN", argv
[1]);
1893 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1897 static NICKSERV_FUNC(cmd_rename_handle
)
1899 struct handle_info
*hi
;
1900 struct userNode
*uNode
;
1904 NICKSERV_MIN_PARMS(3);
1905 if(nickserv_conf
.force_handles_lowercase
)
1906 irc_strtolower(argv
[2]);
1907 if (!(hi
= get_victim_oper(user
, argv
[1])))
1909 if (!is_valid_handle(argv
[2])) {
1910 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1913 if (get_handle_info(argv
[2])) {
1914 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1917 if(strlen(argv
[2]) > 30)
1919 reply("NMSG_HANDLE_TOLONG", argv
[2], 30);
1923 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
1925 if( (rc
= ldap_rename_account(hi
->handle
, argv
[2])) != LDAP_SUCCESS
) {
1926 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
1932 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1933 hi
->handle
= strdup(argv
[2]);
1934 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1935 for (nn
=0; nn
<rf_list_used
; nn
++)
1936 rf_list
[nn
](hi
, old_handle
, rf_list_extra
[nn
]);
1938 if (nickserv_conf
.sync_log
) {
1939 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1940 irc_rename(uNode
, hi
->handle
);
1942 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1945 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1946 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_RENAMED",
1947 user
->handle_info
->handle
, old_handle
, hi
->handle
);
1953 static failpw_func_t
*failpw_func_list
;
1954 static void **failpw_func_list_extra
;
1955 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1958 reg_failpw_func(failpw_func_t func
, void *extra
)
1960 if (failpw_func_used
== failpw_func_size
) {
1961 if (failpw_func_size
) {
1962 failpw_func_size
<<= 1;
1963 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1964 failpw_func_list_extra
= realloc(failpw_func_list_extra
, failpw_func_size
*sizeof(void*));
1966 failpw_func_size
= 8;
1967 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1968 failpw_func_list_extra
= malloc(failpw_func_size
*sizeof(void*));
1971 failpw_func_list
[failpw_func_used
] = func
;
1972 failpw_func_list_extra
[failpw_func_used
++] = extra
;
1976 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1978 * called by nefariouses enhanced AC login-on-connect code
1981 struct handle_info
*loc_auth(char *handle
, char *password
, char *userhost
)
1983 int pw_arg
, used
, maxlogins
;
1986 struct handle_info
*hi
;
1987 struct userNode
*other
;
1989 int ldap_result
= LDAP_SUCCESS
;
1993 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1997 if(nickserv_conf
.ldap_enable
) {
1998 ldap_result
= ldap_check_auth(handle
, password
);
1999 if(ldap_result
!= LDAP_SUCCESS
) {
2008 if (!checkpass(password
, hi
->passwd
)) {
2013 /* ldap libs are present but we are not using them... */
2014 if( !nickserv_conf
.ldap_enable
) {
2018 if (!checkpass(password
, hi
->passwd
)) {
2022 else if( (!hi
) && ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2023 /* user not found, but authed to ldap successfully..
2024 * create the account.
2029 /* Add a *@* mask */
2030 /* TODO if userhost is not null, build mask based on that. */
2031 if(nickserv_conf
.default_hostmask
)
2034 return NULL
; /* They dont have a *@* mask so they can't loc */
2036 if(!(hi
= nickserv_register(NULL
, NULL
, handle
, password
, 0))) {
2037 return 0; /* couldn't add the user for some reason */
2040 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2042 if(nickserv_conf
.email_required
) {
2047 nickserv_set_email_addr(hi
, email
);
2051 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2052 string_list_append(hi
->masks
, mask_canonicalized
);
2054 if(nickserv_conf
.sync_log
)
2055 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, "@", handle
);
2059 /* Still no account, so just fail out */
2064 /* We don't know the users hostname, or anything because they
2065 * havn't registered yet. So we can only allow LOC if your
2066 * account has *@* as a hostmask.
2068 * UPDATE: New nefarious LOC supports u@h
2078 buf
= strdup(userhost
);
2079 ident
= mysep(&buf
, "@");
2080 realhost
= mysep(&buf
, ":");
2081 ip
= mysep(&buf
, ":");
2082 if(!ip
|| !realhost
|| !ident
) {
2084 return NULL
; /* Invalid AC request, just quit */
2086 uh
= malloc(strlen(userhost
));
2087 ui
= malloc(strlen(userhost
));
2088 sprintf(uh
, "%s@%s", ident
, realhost
);
2089 sprintf(ui
, "%s@%s", ident
, ip
);
2090 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2092 if(match_ircglob(uh
, hi
->masks
->list
[ii
])
2093 || match_ircglob(ui
, hi
->masks
->list
[ii
]))
2105 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
2107 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
2117 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2121 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2122 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2123 if (++used
>= maxlogins
) {
2127 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2131 static NICKSERV_FUNC(cmd_auth
)
2133 char *privv
[MAXNUMPARAMS
];
2135 int pw_arg
, used
, maxlogins
;
2136 struct handle_info
*hi
;
2139 struct userNode
*other
;
2141 int ldap_result
= LDAP_OTHER
;
2145 if (user
->handle_info
) {
2146 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2149 if (IsStamped(user
)) {
2150 /* Unauthenticated users might still have been stamped
2151 previously and could therefore have a hidden host;
2152 do not allow them to authenticate. */
2153 reply("NSMSG_STAMPED_AUTH");
2160 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
2161 } else if (argc
== 2) {
2164 if (nickserv_conf
.disable_nicks
) {
2165 hi
= get_handle_info(user
->nick
);
2167 /* try to look up their handle from their nick */
2168 /* TODO: handle ldap auth on nickserv style networks, too */
2169 struct nick_info
*ni
;
2170 ni
= get_nick_info(user
->nick
);
2172 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
2178 handle
= hi
->handle
;
2180 handle
= user
->nick
;
2183 reply("MSG_MISSING_PARAMS", argv
[0]);
2184 svccmd_send_help_brief(user
, nickserv
, cmd
);
2189 if(strchr(argv
[1], '<') || strchr(handle
, '>')) {
2190 reply("NSMSG_NO_ANGLEBRACKETS");
2193 if (!is_valid_handle(handle
)) {
2194 reply("NSMSG_BAD_HANDLE", handle
);
2198 if(nickserv_conf
.ldap_enable
) {
2199 ldap_result
= ldap_check_auth(handle
, passwd
);
2200 /* Get the users email address and update it */
2201 if(ldap_result
== LDAP_SUCCESS
) {
2203 if((rc
= ldap_get_user_info(handle
, &email
) != LDAP_SUCCESS
))
2205 if(nickserv_conf
.email_required
) {
2206 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc
));
2211 else if(ldap_result
!= LDAP_INVALID_CREDENTIALS
) {
2212 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2220 if(nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_SUCCESS
&& nickserv_conf
.ldap_autocreate
) {
2221 /* user not found, but authed to ldap successfully..
2222 * create the account.
2225 if(!(hi
= nickserv_register(user
, NULL
, argv
[1], argv
[2], 0))) {
2226 reply("NSMSG_UNABLE_TO_ADD");
2227 return 0; /* couldn't add the user for some reason */
2229 /* Add a *@* mask */
2230 if(nickserv_conf
.default_hostmask
)
2233 mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2236 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
2237 string_list_append(hi
->masks
, mask_canonicalized
);
2240 nickserv_set_email_addr(hi
, email
);
2243 if(nickserv_conf
.sync_log
)
2244 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
);
2248 reply("NSMSG_HANDLE_NOT_FOUND");
2254 /* Responses from here on look up the language used by the handle they asked about. */
2255 if (!valid_user_for(user
, hi
)) {
2256 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
2257 send_message_type(4, user
, cmd
->parent
->bot
,
2258 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
2261 send_message_type(4, user
, cmd
->parent
->bot
,
2262 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
2264 argv
[pw_arg
] = "BADMASK";
2268 if( ( nickserv_conf
.ldap_enable
&& ldap_result
== LDAP_INVALID_CREDENTIALS
) ||
2269 ( (!nickserv_conf
.ldap_enable
) && (!checkpass(passwd
, hi
->passwd
)) ) ) {
2271 if (!checkpass(passwd
, hi
->passwd
)) {
2274 send_message_type(4, user
, cmd
->parent
->bot
,
2275 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
2276 argv
[pw_arg
] = "BADPASS";
2277 for (n
=0; n
<failpw_func_used
; n
++)
2278 failpw_func_list
[n
](user
, hi
, failpw_func_list_extra
[n
]);
2279 if (nickserv_conf
.autogag_enabled
) {
2280 if (!user
->auth_policer
.params
) {
2281 user
->auth_policer
.last_req
= now
;
2282 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
2284 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
2286 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
2287 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
2288 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
2290 argv
[pw_arg
] = "GAGGED";
2295 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2296 send_message_type(4, user
, cmd
->parent
->bot
,
2297 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2298 argv
[pw_arg
] = "SUSPENDED";
2301 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2302 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2303 if (++used
>= maxlogins
) {
2304 send_message_type(4, user
, cmd
->parent
->bot
,
2305 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2307 argv
[pw_arg
] = "MAXLOGINS";
2312 set_user_handle_info(user
, hi
, 1);
2313 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2314 reply("NSMSG_PLEASE_SET_EMAIL");
2315 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2316 reply("NSMSG_WEAK_PASSWORD");
2317 if (hi
->passwd
[0] != '$')
2318 cryptpass(passwd
, hi
->passwd
);
2320 /* If a channel was waiting for this user to auth,
2321 * finish adding them */
2322 process_adduser_pending(user
);
2324 reply("NSMSG_AUTH_SUCCESS");
2327 /* Set +x if autohide is on */
2328 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2329 irc_umode(user
, "+x");
2331 if(!IsOper(user
)) /* If they arnt already opered.. */
2333 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2334 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2336 if (nickserv_conf
.auto_admin_privs
[0]) {
2337 irc_raw_privs(user
, nickserv_conf
.auto_admin_privs
);
2338 privc
= split_line(strdup(nickserv_conf
.auto_admin_privs
), false, MAXNUMPARAMS
, privv
);
2339 for (i
= 0; i
< privc
; i
++) {
2340 client_modify_priv_by_name(user
, privv
[i
], 1);
2343 irc_umode(user
,nickserv_conf
.auto_admin
);
2344 reply("NSMSG_AUTO_OPER_ADMIN");
2346 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2348 if (nickserv_conf
.auto_oper_privs
[0]) {
2349 irc_raw_privs(user
, nickserv_conf
.auto_oper_privs
);
2350 privc
= split_line(strdup(nickserv_conf
.auto_oper_privs
), false, MAXNUMPARAMS
, privv
);
2351 for (i
= 0; i
< privc
; i
++) {
2352 client_modify_priv_by_name(user
, privv
[i
], 1);
2355 irc_umode(user
,nickserv_conf
.auto_oper
);
2356 reply("NSMSG_AUTO_OPER");
2360 /* Wipe out the pass for the logs */
2362 if (!hi
->masks
->used
) {
2364 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2365 if (irc_in_addr_is_valid(user
->ip
) && irc_pton(&ip
, NULL
, user
->hostname
))
2366 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
2369 argv
[pw_arg
] = "****";
2373 static allowauth_func_t
*allowauth_func_list
;
2374 static void **allowauth_func_list_extra
;
2375 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2378 reg_allowauth_func(allowauth_func_t func
, void *extra
)
2380 if (allowauth_func_used
== allowauth_func_size
) {
2381 if (allowauth_func_size
) {
2382 allowauth_func_size
<<= 1;
2383 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2384 allowauth_func_list_extra
= realloc(allowauth_func_list_extra
, allowauth_func_size
*sizeof(void*));
2386 allowauth_func_size
= 8;
2387 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2388 allowauth_func_list_extra
= malloc(allowauth_func_size
*sizeof(void*));
2391 allowauth_func_list
[allowauth_func_used
] = func
;
2392 allowauth_func_list_extra
[allowauth_func_used
++] = extra
;
2395 static NICKSERV_FUNC(cmd_allowauth
)
2397 struct userNode
*target
;
2398 struct handle_info
*hi
;
2401 NICKSERV_MIN_PARMS(2);
2402 if (!(target
= GetUserH(argv
[1]))) {
2403 reply("MSG_NICK_UNKNOWN", argv
[1]);
2406 if (target
->handle_info
) {
2407 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2410 if (IsStamped(target
)) {
2411 /* Unauthenticated users might still have been stamped
2412 previously and could therefore have a hidden host;
2413 do not allow them to authenticate to an account. */
2414 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2419 else if (!(hi
= get_handle_info(argv
[2]))) {
2420 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2424 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2425 reply("MSG_USER_OUTRANKED", hi
->handle
);
2428 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2429 || (hi
->opserv_level
> 0))
2430 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2431 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2434 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2435 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2436 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2437 if (nickserv_conf
.email_enabled
)
2438 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2440 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2441 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2443 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2445 for (n
=0; n
<allowauth_func_used
; n
++)
2446 allowauth_func_list
[n
](user
, target
, hi
, allowauth_func_list_extra
[n
]);
2450 static NICKSERV_FUNC(cmd_authcookie
)
2452 struct handle_info
*hi
;
2454 NICKSERV_MIN_PARMS(2);
2455 if (user
->handle_info
) {
2456 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2459 if (IsStamped(user
)) {
2460 /* Unauthenticated users might still have been stamped
2461 previously and could therefore have a hidden host;
2462 do not allow them to authenticate to an account. */
2463 reply("NSMSG_STAMPED_AUTHCOOKIE");
2466 if (!(hi
= get_handle_info(argv
[1]))) {
2467 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2470 if (!hi
->email_addr
) {
2471 reply("MSG_SET_EMAIL_ADDR");
2474 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2478 static NICKSERV_FUNC(cmd_delcookie
)
2480 struct handle_info
*hi
;
2482 hi
= user
->handle_info
;
2484 reply("NSMSG_NO_COOKIE");
2487 switch (hi
->cookie
->type
) {
2490 reply("NSMSG_MUST_TIME_OUT");
2493 nickserv_eat_cookie(hi
->cookie
);
2494 reply("NSMSG_ATE_COOKIE");
2500 static NICKSERV_FUNC(cmd_odelcookie
)
2502 struct handle_info
*hi
;
2504 NICKSERV_MIN_PARMS(2);
2506 if (!(hi
= get_victim_oper(user
, argv
[1])))
2510 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2514 switch (hi
->cookie
->type
) {
2516 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2518 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2520 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2521 /* Falied to update password in ldap, but still
2522 * updated it here.. what should we do? */
2523 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2528 if (nickserv_conf
.sync_log
)
2529 SyncLog("ACCOUNTACC %s", hi
->handle
);
2531 case PASSWORD_CHANGE
:
2538 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2539 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2543 nickserv_eat_cookie(hi
->cookie
);
2544 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2549 static NICKSERV_FUNC(cmd_resetpass
)
2551 struct handle_info
*hi
;
2552 char crypted
[MD5_CRYPT_LENGTH
];
2555 NICKSERV_MIN_PARMS(3);
2556 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2560 if (user
->handle_info
) {
2561 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2564 if (IsStamped(user
)) {
2565 /* Unauthenticated users might still have been stamped
2566 previously and could therefore have a hidden host;
2567 do not allow them to activate an account. */
2568 reply("NSMSG_STAMPED_RESETPASS");
2571 if (!(hi
= get_handle_info(argv
[1]))) {
2572 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2575 if (!hi
->email_addr
) {
2576 reply("MSG_SET_EMAIL_ADDR");
2579 cryptpass(argv
[2], crypted
);
2581 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2585 static NICKSERV_FUNC(cmd_cookie
)
2587 struct handle_info
*hi
;
2590 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2593 NICKSERV_MIN_PARMS(3);
2594 if (!(hi
= get_handle_info(argv
[1]))) {
2595 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2601 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2602 reply("NSMSG_HANDLE_SUSPENDED");
2607 reply("NSMSG_NO_COOKIE");
2611 /* Check validity of operation before comparing cookie to
2612 * prohibit guessing by authed users. */
2613 if (user
->handle_info
2614 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2615 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2616 reply("NSMSG_CANNOT_COOKIE");
2620 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2621 reply("NSMSG_BAD_COOKIE");
2625 switch (hi
->cookie
->type
) {
2628 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2630 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2631 /* Falied to update email in ldap, but still
2632 * updated it here.. what should we do? */
2633 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2638 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2639 set_user_handle_info(user
, hi
, 1);
2640 reply("NSMSG_HANDLE_ACTIVATED");
2641 if (nickserv_conf
.sync_log
)
2642 SyncLog("ACCOUNTACC %s", hi
->handle
);
2644 case PASSWORD_CHANGE
:
2646 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2648 if((rc
= ldap_do_modify(hi
->handle
, hi
->cookie
->data
, NULL
)) != LDAP_SUCCESS
) {
2649 /* Falied to update email in ldap, but still
2650 * updated it here.. what should we do? */
2651 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2656 set_user_handle_info(user
, hi
, 1);
2657 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2658 reply("NSMSG_PASSWORD_CHANGED");
2659 if (nickserv_conf
.sync_log
)
2660 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2664 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2666 if((rc
= ldap_do_modify(hi
->handle
, NULL
, hi
->cookie
->data
)) != LDAP_SUCCESS
) {
2667 /* Falied to update email in ldap, but still
2668 * updated it here.. what should we do? */
2669 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc
));
2674 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2676 * This should only happen if an OREGISTER was sent. Require
2677 * email must be enabled! - SiRVulcaN
2679 if (nickserv_conf
.sync_log
)
2680 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2683 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2684 reply("NSMSG_EMAIL_CHANGED");
2685 if (nickserv_conf
.sync_log
)
2686 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2689 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2690 set_user_handle_info(user
, hi
, 1);
2691 nickserv_addmask(user
, hi
, mask
);
2692 reply("NSMSG_AUTH_SUCCESS");
2697 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2698 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2702 nickserv_eat_cookie(hi
->cookie
);
2704 process_adduser_pending(user
);
2709 static NICKSERV_FUNC(cmd_oregnick
) {
2711 struct handle_info
*target
;
2712 struct nick_info
*ni
;
2714 NICKSERV_MIN_PARMS(3);
2715 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2718 if (!is_registerable_nick(nick
)) {
2719 reply("NSMSG_BAD_NICK", nick
);
2722 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2724 reply("NSMSG_NICK_EXISTS", nick
);
2727 register_nick(nick
, target
);
2728 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2732 static NICKSERV_FUNC(cmd_regnick
) {
2734 struct nick_info
*ni
;
2736 if (!is_registerable_nick(user
->nick
)) {
2737 reply("NSMSG_BAD_NICK", user
->nick
);
2740 /* count their nicks, see if it's too many */
2741 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2742 if (n
>= nickserv_conf
.nicks_per_handle
) {
2743 reply("NSMSG_TOO_MANY_NICKS");
2746 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2748 reply("NSMSG_NICK_EXISTS", user
->nick
);
2751 register_nick(user
->nick
, user
->handle_info
);
2752 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2756 static NICKSERV_FUNC(cmd_pass
)
2758 struct handle_info
*hi
;
2759 char *old_pass
, *new_pass
;
2760 char crypted
[MD5_CRYPT_LENGTH
+1];
2765 NICKSERV_MIN_PARMS(3);
2766 hi
= user
->handle_info
;
2770 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2773 if(nickserv_conf
.ldap_enable
) {
2774 ldap_result
= ldap_check_auth(hi
->handle
, old_pass
);
2775 if(ldap_result
!= LDAP_SUCCESS
) {
2776 if(ldap_result
== LDAP_INVALID_CREDENTIALS
)
2777 reply("NSMSG_PASSWORD_INVALID");
2779 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result
));
2784 if (!checkpass(old_pass
, hi
->passwd
)) {
2785 argv
[1] = "BADPASS";
2786 reply("NSMSG_PASSWORD_INVALID");
2789 cryptpass(new_pass
, crypted
);
2791 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
2793 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
2794 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
2799 //cryptpass(new_pass, hi->passwd);
2800 strcpy(hi
->passwd
, crypted
);
2801 if (nickserv_conf
.sync_log
)
2802 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2804 reply("NSMSG_PASS_SUCCESS");
2809 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2812 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2813 for (i
=0; i
<hi
->masks
->used
; i
++) {
2814 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2815 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2820 string_list_append(hi
->masks
, new_mask
);
2821 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2825 static NICKSERV_FUNC(cmd_addmask
)
2828 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2829 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2833 if (!is_gline(argv
[1])) {
2834 reply("NSMSG_MASK_INVALID", argv
[1]);
2837 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2841 static NICKSERV_FUNC(cmd_oaddmask
)
2843 struct handle_info
*hi
;
2845 NICKSERV_MIN_PARMS(3);
2846 if (!(hi
= get_victim_oper(user
, argv
[1])))
2848 return nickserv_addmask(user
, hi
, argv
[2]);
2852 nickserv_delmask(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
, int force
)
2855 for (i
=0; i
<hi
->masks
->used
; i
++) {
2856 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2857 char *old_mask
= hi
->masks
->list
[i
];
2858 if (hi
->masks
->used
== 1 && !force
) {
2859 reply("NSMSG_DELMASK_NOTLAST");
2862 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2863 reply("NSMSG_DELMASK_SUCCESS", old_mask
);
2868 reply("NSMSG_DELMASK_NOT_FOUND");
2872 static NICKSERV_FUNC(cmd_delmask
)
2874 NICKSERV_MIN_PARMS(2);
2875 return nickserv_delmask(cmd
, user
, user
->handle_info
, argv
[1], 0);
2878 static NICKSERV_FUNC(cmd_odelmask
)
2880 struct handle_info
*hi
;
2881 NICKSERV_MIN_PARMS(3);
2882 if (!(hi
= get_victim_oper(user
, argv
[1])))
2884 return nickserv_delmask(cmd
, user
, hi
, argv
[2], 1);
2888 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2889 unsigned int nn
, add
= 1, pos
;
2890 unsigned long added
, removed
, flag
;
2892 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2894 case '+': add
= 1; break;
2895 case '-': add
= 0; break;
2897 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2898 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2901 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2902 /* cheesy avoidance of looking up the flag name.. */
2903 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2906 flag
= 1 << (pos
- 1);
2908 added
|= flag
, removed
&= ~flag
;
2910 removed
|= flag
, added
&= ~flag
;
2915 *premoved
= removed
;
2920 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2922 unsigned long before
, after
, added
, removed
;
2923 struct userNode
*uNode
;
2925 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2926 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2928 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2929 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2931 /* Strip helping flag if they're only a support helper and not
2932 * currently in #support. */
2933 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2934 struct channelList
*schannels
;
2936 schannels
= chanserv_support_channels();
2937 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2938 if (find_handle_in_channel(schannels
->list
[ii
], hi
, NULL
))
2940 if (ii
== schannels
->used
)
2941 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2944 if (after
&& !before
) {
2945 /* Add user to current helper list. */
2946 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2947 userList_append(&curr_helpers
, uNode
);
2948 } else if (!after
&& before
) {
2949 /* Remove user from current helper list. */
2950 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2951 userList_remove(&curr_helpers
, uNode
);
2958 set_list(struct svccmd
*cmd
, struct userNode
*user
, struct handle_info
*hi
, int override
)
2962 char *set_display
[] = {
2963 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2964 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2965 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2968 reply("NSMSG_SETTING_LIST");
2969 reply("NSMSG_SETTING_LIST_HEADER");
2971 /* Do this so options are presented in a consistent order. */
2972 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2973 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2974 opt(cmd
, user
, hi
, override
, 0, NULL
);
2975 reply("NSMSG_SETTING_LIST_END");
2978 static NICKSERV_FUNC(cmd_set
)
2980 struct handle_info
*hi
;
2983 hi
= user
->handle_info
;
2985 set_list(cmd
, user
, hi
, 0);
2988 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2989 reply("NSMSG_INVALID_OPTION", argv
[1]);
2992 return opt(cmd
, user
, hi
, 0, argc
-1, argv
+1);
2995 static NICKSERV_FUNC(cmd_oset
)
2997 struct handle_info
*hi
;
3000 NICKSERV_MIN_PARMS(2);
3002 if (!(hi
= get_victim_oper(user
, argv
[1])))
3006 set_list(cmd
, user
, hi
, 0);
3010 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
3011 reply("NSMSG_INVALID_OPTION", argv
[2]);
3015 return opt(cmd
, user
, hi
, 1, argc
-2, argv
+2);
3018 static OPTION_FUNC(opt_info
)
3022 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
3024 hi
->infoline
= NULL
;
3026 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
3030 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
3031 reply("NSMSG_SET_INFO", info
);
3035 static OPTION_FUNC(opt_width
)
3038 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
3040 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
3041 hi
->screen_width
= MIN_LINE_SIZE
;
3042 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3043 hi
->screen_width
= MAX_LINE_SIZE
;
3045 reply("NSMSG_SET_WIDTH", hi
->screen_width
);
3049 static OPTION_FUNC(opt_tablewidth
)
3052 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
3054 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
3055 hi
->table_width
= MIN_LINE_SIZE
;
3056 else if (hi
->screen_width
> MAX_LINE_SIZE
)
3057 hi
->table_width
= MAX_LINE_SIZE
;
3059 reply("NSMSG_SET_TABLEWIDTH", hi
->table_width
);
3063 static OPTION_FUNC(opt_color
)
3066 if (enabled_string(argv
[1]))
3067 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
3068 else if (disabled_string(argv
[1]))
3069 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
3071 reply("MSG_INVALID_BINARY", argv
[1]);
3076 reply("NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
3080 static OPTION_FUNC(opt_privmsg
)
3083 if (enabled_string(argv
[1]))
3084 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
3085 else if (disabled_string(argv
[1]))
3086 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
3088 reply("MSG_INVALID_BINARY", argv
[1]);
3093 reply("NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
3097 static OPTION_FUNC(opt_autohide
)
3100 if (enabled_string(argv
[1]))
3101 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
3102 else if (disabled_string(argv
[1]))
3103 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
3105 reply("MSG_INVALID_BINARY", argv
[1]);
3110 reply("NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
3114 static OPTION_FUNC(opt_style
)
3119 if (!irccasecmp(argv
[1], "Clean"))
3120 hi
->userlist_style
= HI_STYLE_CLEAN
;
3121 else if (!irccasecmp(argv
[1], "Advanced"))
3122 hi
->userlist_style
= HI_STYLE_ADVANCED
;
3123 else if (!irccasecmp(argv
[1], "Classic"))
3124 hi
->userlist_style
= HI_STYLE_CLASSIC
;
3125 else /* Default to normal */
3126 hi
->userlist_style
= HI_STYLE_NORMAL
;
3127 } /* TODO: give error if unknow style is chosen */
3129 switch (hi
->userlist_style
) {
3130 case HI_STYLE_ADVANCED
:
3133 case HI_STYLE_CLASSIC
:
3136 case HI_STYLE_CLEAN
:
3139 case HI_STYLE_NORMAL
:
3144 reply("NSMSG_SET_STYLE", style
);
3148 static OPTION_FUNC(opt_announcements
)
3153 if (enabled_string(argv
[1]))
3154 hi
->announcements
= 'y';
3155 else if (disabled_string(argv
[1]))
3156 hi
->announcements
= 'n';
3157 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
3158 hi
->announcements
= '?';
3160 reply("NSMSG_INVALID_ANNOUNCE", argv
[1]);
3165 switch (hi
->announcements
) {
3166 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
3167 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
3168 case '?': choice
= "default"; break;
3169 default: choice
= "unknown"; break;
3171 reply("NSMSG_SET_ANNOUNCEMENTS", choice
);
3175 static OPTION_FUNC(opt_password
)
3177 char crypted
[MD5_CRYPT_LENGTH
+1];
3182 reply("NSMSG_USE_CMD_PASS");
3186 cryptpass(argv
[1], crypted
);
3188 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3190 if((rc
= ldap_do_modify(hi
->handle
, crypted
, NULL
)) != LDAP_SUCCESS
) {
3191 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3196 strcpy(hi
->passwd
, crypted
);
3197 if (nickserv_conf
.sync_log
)
3198 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
3200 reply("NSMSG_SET_PASSWORD", "***");
3204 static OPTION_FUNC(opt_flags
)
3207 unsigned int ii
, flen
;
3210 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3215 nickserv_apply_flags(user
, hi
, argv
[1]);
3217 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
3218 if (hi
->flags
& (1 << ii
))
3219 flags
[flen
++] = handle_flags
[ii
];
3222 reply("NSMSG_SET_FLAGS", flags
);
3224 reply("NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
3228 static OPTION_FUNC(opt_email
)
3232 if (!valid_email(argv
[1])) {
3233 reply("NSMSG_BAD_EMAIL_ADDR");
3236 if ((str
= mail_prohibited_address(argv
[1]))) {
3237 reply("NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
3240 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
3241 reply("NSMSG_EMAIL_SAME");
3243 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
3246 if(nickserv_conf
.ldap_enable
&& nickserv_conf
.ldap_admin_dn
) {
3248 if((rc
= ldap_do_modify(hi
->handle
, NULL
, argv
[1])) != LDAP_SUCCESS
) {
3249 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3254 nickserv_set_email_addr(hi
, argv
[1]);
3256 nickserv_eat_cookie(hi
->cookie
);
3257 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3260 reply("NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
3264 static OPTION_FUNC(opt_maxlogins
)
3266 unsigned char maxlogins
;
3268 maxlogins
= strtoul(argv
[1], NULL
, 0);
3269 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
3270 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
3273 hi
->maxlogins
= maxlogins
;
3275 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
3276 reply("NSMSG_SET_MAXLOGINS", maxlogins
);
3280 static OPTION_FUNC(opt_advanced
)
3283 if (enabled_string(argv
[1]))
3284 HANDLE_SET_FLAG(hi
, ADVANCED
);
3285 else if (disabled_string(argv
[1]))
3286 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
3288 reply("MSG_INVALID_BINARY", argv
[1]);
3293 reply("NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
3297 static OPTION_FUNC(opt_language
)
3299 struct language
*lang
;
3301 lang
= language_find(argv
[1]);
3302 if (irccasecmp(lang
->name
, argv
[1]))
3303 reply("NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
3304 hi
->language
= lang
;
3306 reply("NSMSG_SET_LANGUAGE", hi
->language
->name
);
3310 static OPTION_FUNC(opt_karma
)
3313 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3318 if (argv
[1][0] == '+' && isdigit(argv
[1][1])) {
3319 hi
->karma
+= strtoul(argv
[1] + 1, NULL
, 10);
3320 } else if (argv
[1][0] == '-' && isdigit(argv
[1][1])) {
3321 hi
->karma
-= strtoul(argv
[1] + 1, NULL
, 10);
3323 send_message(user
, nickserv
, "NSMSG_INVALID_KARMA", argv
[1]);
3327 send_message(user
, nickserv
, "NSMSG_SET_KARMA", hi
->karma
);
3331 /* Called from opserv from cmd_access */
3333 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
3334 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
3336 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
3337 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
3338 && (user
->handle_info
->opserv_level
< 1000))) {
3339 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
3342 if ((user
->handle_info
->opserv_level
< new_level
)
3343 || ((user
->handle_info
->opserv_level
== new_level
)
3344 && (user
->handle_info
->opserv_level
< 1000))) {
3345 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
3348 if (user
->handle_info
== target
) {
3349 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
3353 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_oper_group_dn
) && *(nickserv_conf
.ldap_admin_dn
)) {
3355 if(new_level
> nickserv_conf
.ldap_oper_group_level
)
3356 rc
= ldap_add2group(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3358 rc
= ldap_delfromgroup(target
->handle
, nickserv_conf
.ldap_oper_group_dn
);
3359 if(rc
!= LDAP_SUCCESS
&& rc
!= LDAP_TYPE_OR_VALUE_EXISTS
&& rc
!= LDAP_NO_SUCH_ATTRIBUTE
) {
3360 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3364 if(nickserv_conf
.ldap_enable
&& *(nickserv_conf
.ldap_field_oslevel
) && *(nickserv_conf
.ldap_admin_dn
)) {
3366 if((rc
= ldap_do_oslevel(target
->handle
, new_level
, target
->opserv_level
)) != LDAP_SUCCESS
) {
3367 send_message(user
, bot
, "NSMSG_LDAP_FAIL", ldap_err2string(rc
));
3372 if (target
->opserv_level
== new_level
)
3374 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
3375 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
3376 target
->opserv_level
= new_level
;
3380 static OPTION_FUNC(opt_level
)
3385 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3389 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
3390 reply("NSMSG_SET_LEVEL", hi
->opserv_level
);
3394 static OPTION_FUNC(opt_epithet
)
3396 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
3398 struct userNode
*target
, *next_un
;
3401 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3405 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
3409 if ((epithet
[0] == '*') && !epithet
[1])
3412 hi
->epithet
= strdup(epithet
);
3414 for (target
= hi
->users
; target
; target
= next_un
) {
3415 irc_swhois(nickserv
, target
, hi
->epithet
);
3417 next_un
= target
->next_authed
;
3422 reply("NSMSG_SET_EPITHET", hi
->epithet
);
3424 reply("NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
3428 static OPTION_FUNC(opt_title
)
3434 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
3436 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3441 if(!strcmp(title
, "*")) {
3443 hi
->fakehost
= NULL
;
3446 if (strchr(title
, '.')) {
3447 reply("NSMSG_TITLE_INVALID");
3450 /* Alphanumeric titles only. */
3451 for(sptr
= title
; *sptr
; sptr
++) {
3452 if(!isalnum(*sptr
) && *sptr
!= '-') {
3453 reply("NSMSG_TITLE_INVALID");
3457 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
3458 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
3459 reply("NSMSG_TITLE_TRUNCATED");
3463 hi
->fakehost
= malloc(strlen(title
)+2);
3464 hi
->fakehost
[0] = '.';
3465 strcpy(hi
->fakehost
+1, title
);
3468 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
3469 title
= hi
->fakehost
+ 1;
3471 /* If theres no title set then the default title will therefore
3472 be the first part of hidden_host in x3.conf, so for
3473 consistency with opt_fakehost we will print this here.
3474 This isnt actually used in P10, its just handled to keep from crashing... */
3475 char *hs
, *hidden_suffix
, *rest
;
3477 hs
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
3478 hidden_suffix
= strdup(hs
);
3480 /* Yes we do this twice */
3481 if((rest
= strchr(hidden_suffix
, '.')))
3484 title
= hidden_suffix
;
3488 /* A lame default if someone configured hidden_host to something lame */
3489 title
= strdup("users");
3490 free(hidden_suffix
);
3496 none
= user_find_message(user
, "MSG_NONE");
3497 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
? title
: none
);
3502 check_vhost(char *vhost
, struct userNode
*user
, struct svccmd
*cmd
)
3506 // check for a dot in the vhost
3507 if(strchr(vhost
, '.') == NULL
) {
3508 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3512 // check for a @ in the vhost
3513 if(strchr(vhost
, '@') != NULL
) {
3514 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3518 // check for denied words, inspired by monk at paki.sex
3519 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3520 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3521 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3526 // check for ircu's HOSTLEN length.
3527 if(strlen(vhost
) >= HOSTLEN
) {
3528 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3532 /* This can be handled by the regex now if desired.
3533 if (vhost[strspn(vhost, "0123456789.")]) {
3534 hostname = vhost + strlen(vhost);
3535 for (depth = 1; depth && (hostname > vhost); depth--) {
3537 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3540 if (*hostname == '.') hostname++; * advance past last dot we saw *
3541 if(strlen(hostname) > 4) {
3542 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3547 /* test either regex or as valid handle */
3548 if (nickserv_conf
.valid_fakehost_regex_set
) {
3549 int err
= regexec(&nickserv_conf
.valid_fakehost_regex
, vhost
, 0, 0, 0);
3552 buff
[regerror(err
, &nickserv_conf
.valid_fakehost_regex
, buff
, sizeof(buff
))] = 0;
3553 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
3555 if(err
== REG_NOMATCH
) {
3556 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost
);
3565 static OPTION_FUNC(opt_fakehost
)
3569 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3571 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3576 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3577 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3580 if (!strcmp(fake
, "*")) {
3583 hi
->fakehost
= NULL
;
3586 else if (!check_vhost(argv
[1], user
, cmd
)) {
3587 /* check_vhost takes care of error reply */
3593 hi
->fakehost
= strdup(fake
);
3596 fake
= hi
->fakehost
;
3598 fake
= generate_fakehost(hi
);
3600 /* Tell them we set the host */
3602 fake
= user_find_message(user
, "MSG_NONE");
3603 reply("NSMSG_SET_FAKEHOST", fake
);
3607 static OPTION_FUNC(opt_note
)
3610 reply("MSG_SETTING_PRIVILEGED", argv
[0]);
3615 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3620 if ((text
[0] == '*') && !text
[1])
3623 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3628 reply("NSMSG_SET_NOTE", hi
->note
? hi
->note
->note
: user_find_message(user
, "MSG_NONE"));
3632 static NICKSERV_FUNC(cmd_reclaim
)
3634 struct handle_info
*hi
;
3635 struct nick_info
*ni
;
3636 struct userNode
*victim
;
3638 NICKSERV_MIN_PARMS(2);
3639 hi
= user
->handle_info
;
3640 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3642 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3645 if (ni
->owner
!= user
->handle_info
) {
3646 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3649 victim
= GetUserH(ni
->nick
);
3651 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3654 if (victim
== user
) {
3655 reply("NSMSG_NICK_USER_YOU");
3658 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3659 switch (nickserv_conf
.reclaim_action
) {
3660 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3661 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3662 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3663 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3668 static NICKSERV_FUNC(cmd_unregnick
)
3671 struct handle_info
*hi
;
3672 struct nick_info
*ni
;
3674 hi
= user
->handle_info
;
3675 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3676 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3678 reply("NSMSG_UNKNOWN_NICK", nick
);
3681 if (hi
!= ni
->owner
) {
3682 reply("NSMSG_NOT_YOUR_NICK", nick
);
3685 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3690 static NICKSERV_FUNC(cmd_ounregnick
)
3692 struct nick_info
*ni
;
3694 NICKSERV_MIN_PARMS(2);
3695 if (!(ni
= get_nick_info(argv
[1]))) {
3696 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3699 if (!oper_outranks(user
, ni
->owner
))
3701 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3706 static NICKSERV_FUNC(cmd_unregister
)
3708 struct handle_info
*hi
;
3711 NICKSERV_MIN_PARMS(2);
3712 hi
= user
->handle_info
;
3715 if (checkpass(passwd
, hi
->passwd
)) {
3716 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3721 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3722 reply("NSMSG_PASSWORD_INVALID");
3727 static NICKSERV_FUNC(cmd_ounregister
)
3729 struct handle_info
*hi
;
3730 char reason
[MAXLEN
];
3733 NICKSERV_MIN_PARMS(2);
3734 if (!(hi
= get_victim_oper(user
, argv
[1])))
3737 if (HANDLE_FLAGGED(hi
, NODELETE
)) {
3738 reply("NSMSG_UNREGISTER_NODELETE", hi
->handle
);
3742 force
= IsOper(user
) && (argc
> 2) && !irccasecmp(argv
[2], "force");
3744 ((hi
->flags
& nickserv_conf
.ounregister_flags
)
3746 || (hi
->last_quit_host
[0] && ((unsigned)(now
- hi
->lastseen
) < nickserv_conf
.ounregister_inactive
)))) {
3747 reply((IsOper(user
) ? "NSMSG_UNREGISTER_MUST_FORCE" : "NSMSG_UNREGISTER_CANNOT_FORCE"), hi
->handle
);
3750 snprintf(reason
, sizeof(reason
), "%s unregistered account %s.", user
->handle_info
->handle
, hi
->handle
);
3751 global_message(MESSAGE_RECIPIENT_STAFF
, reason
);
3752 if(nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
))
3758 static NICKSERV_FUNC(cmd_status
)
3760 if (nickserv_conf
.disable_nicks
) {
3761 reply("NSMSG_GLOBAL_STATS_NONICK",
3762 dict_size(nickserv_handle_dict
));
3764 if (user
->handle_info
) {
3766 struct nick_info
*ni
;
3767 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3768 reply("NSMSG_HANDLE_STATS", cnt
);
3770 reply("NSMSG_HANDLE_NONE");
3772 reply("NSMSG_GLOBAL_STATS",
3773 dict_size(nickserv_handle_dict
),
3774 dict_size(nickserv_nick_dict
));
3779 static NICKSERV_FUNC(cmd_ghost
)
3781 struct userNode
*target
;
3782 char reason
[MAXLEN
];
3784 NICKSERV_MIN_PARMS(2);
3785 if (!(target
= GetUserH(argv
[1]))) {
3786 reply("MSG_NICK_UNKNOWN", argv
[1]);
3789 if (target
== user
) {
3790 reply("NSMSG_CANNOT_GHOST_SELF");
3793 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3794 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3797 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3798 DelUser(target
, nickserv
, 1, reason
);
3799 reply("NSMSG_GHOST_KILLED", argv
[1]);
3803 static NICKSERV_FUNC(cmd_vacation
)
3805 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3806 reply("NSMSG_ON_VACATION");
3811 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3813 struct handle_info
*hi
;
3816 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3818 saxdb_start_record(ctx
, iter_key(it
), 0);
3819 if (hi
->announcements
!= '?') {
3820 flags
[0] = hi
->announcements
;
3822 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3825 struct handle_cookie
*cookie
= hi
->cookie
;
3828 switch (cookie
->type
) {
3829 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3830 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3831 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3832 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3833 default: type
= NULL
; break;
3836 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3837 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3838 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3840 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3841 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3842 saxdb_end_record(ctx
);
3846 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3848 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3850 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3851 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3852 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3853 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3854 saxdb_end_record(ctx
);
3858 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3862 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3863 if (hi
->flags
& (1 << ii
))
3864 flags
[flen
++] = handle_flags
[ii
];
3866 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3869 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3870 if (hi
->last_quit_host
[0])
3871 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3872 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3874 saxdb_write_sint(ctx
, KEY_KARMA
, hi
->karma
);
3875 if (hi
->masks
->used
)
3876 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3877 if (hi
->ignores
->used
)
3878 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3880 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3882 struct string_list
*slist
;
3883 struct nick_info
*ni
;
3885 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3886 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3887 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3891 if (hi
->opserv_level
)
3892 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3893 if (hi
->language
!= lang_C
)
3894 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3895 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3896 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3897 if (hi
->screen_width
)
3898 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3899 if (hi
->table_width
)
3900 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3901 flags
[0] = hi
->userlist_style
;
3903 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3904 saxdb_end_record(ctx
);
3910 static handle_merge_func_t
*handle_merge_func_list
;
3911 static void **handle_merge_func_list_extra
;
3912 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3915 reg_handle_merge_func(handle_merge_func_t func
, void *extra
)
3917 if (handle_merge_func_used
== handle_merge_func_size
) {
3918 if (handle_merge_func_size
) {
3919 handle_merge_func_size
<<= 1;
3920 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3921 handle_merge_func_list_extra
= realloc(handle_merge_func_list_extra
, handle_merge_func_size
*sizeof(void*));
3923 handle_merge_func_size
= 8;
3924 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3925 handle_merge_func_list_extra
= malloc(handle_merge_func_size
*sizeof(void*));
3928 handle_merge_func_list
[handle_merge_func_used
] = func
;
3929 handle_merge_func_list_extra
[handle_merge_func_used
++] = extra
;
3932 static NICKSERV_FUNC(cmd_merge
)
3934 struct handle_info
*hi_from
, *hi_to
;
3935 struct userNode
*last_user
;
3936 struct userData
*cList
, *cListNext
;
3937 unsigned int ii
, jj
, n
;
3939 NICKSERV_MIN_PARMS(3);
3941 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3943 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3945 if (hi_to
== hi_from
) {
3946 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3950 for (n
=0; n
<handle_merge_func_used
; n
++)
3951 handle_merge_func_list
[n
](user
, hi_to
, hi_from
, handle_merge_func_list_extra
[n
]);
3953 /* Append "from" handle's nicks to "to" handle's nick list. */
3955 struct nick_info
*last_ni
;
3956 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3957 last_ni
->next
= hi_from
->nicks
;
3959 while (hi_from
->nicks
) {
3960 hi_from
->nicks
->owner
= hi_to
;
3961 hi_from
->nicks
= hi_from
->nicks
->next
;
3964 /* Merge the hostmasks. */
3965 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3966 char *mask
= hi_from
->masks
->list
[ii
];
3967 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3968 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3970 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3971 string_list_append(hi_to
->masks
, strdup(mask
));
3974 /* Merge the ignores. */
3975 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3976 char *ignore
= hi_from
->ignores
->list
[ii
];
3977 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3978 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3980 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3981 string_list_append(hi_to
->ignores
, strdup(ignore
));
3984 /* Merge the lists of authed users. */
3986 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3987 last_user
->next_authed
= hi_from
->users
;
3989 hi_to
->users
= hi_from
->users
;
3991 /* Repoint the old "from" handle's users. */
3992 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3993 last_user
->handle_info
= hi_to
;
3995 hi_from
->users
= NULL
;
3997 /* Merge channel userlists. */
3998 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3999 struct userData
*cList2
;
4000 cListNext
= cList
->u_next
;
4001 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
4002 if (cList
->channel
== cList2
->channel
)
4004 if (cList2
&& (cList2
->access
>= cList
->access
)) {
4005 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
);
4006 /* keep cList2 in hi_to; remove cList from hi_from */
4007 del_channel_user(cList
, 1);
4010 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
);
4011 /* remove the lower-ranking cList2 from hi_to */
4012 del_channel_user(cList2
, 1);
4014 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
4016 /* cList needs to be moved from hi_from to hi_to */
4017 cList
->handle
= hi_to
;
4018 /* Remove from linked list for hi_from */
4019 assert(!cList
->u_prev
);
4020 hi_from
->channels
= cList
->u_next
;
4022 cList
->u_next
->u_prev
= cList
->u_prev
;
4023 /* Add to linked list for hi_to */
4024 cList
->u_prev
= NULL
;
4025 cList
->u_next
= hi_to
->channels
;
4026 if (hi_to
->channels
)
4027 hi_to
->channels
->u_prev
= cList
;
4028 hi_to
->channels
= cList
;
4032 /* Do they get an OpServ level promotion? */
4033 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
4034 hi_to
->opserv_level
= hi_from
->opserv_level
;
4036 /* What about last seen time? */
4037 if (hi_from
->lastseen
> hi_to
->lastseen
)
4038 hi_to
->lastseen
= hi_from
->lastseen
;
4040 /* New karma is the sum of the two original karmas. */
4041 hi_to
->karma
+= hi_from
->karma
;
4043 /* Does a fakehost carry over? (This intentionally doesn't set it
4044 * for users previously attached to hi_to. They'll just have to
4047 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
4048 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
4050 /* Notify of success. */
4051 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
4052 global_message_args(MESSAGE_RECIPIENT_OPERS
, "NSMSG_ACCOUNT_MERGED", user
->nick
,
4053 user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
4055 /* Unregister the "from" handle. */
4056 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
4057 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
4058 * the process isn't completed.
4064 struct nickserv_discrim
{
4065 unsigned long flags_on
, flags_off
;
4066 time_t min_registered
, max_registered
;
4069 int min_level
, max_level
;
4070 int min_karma
, max_karma
;
4071 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
4072 const char *nickmask
;
4073 const char *hostmask
;
4074 const char *handlemask
;
4075 const char *emailmask
;
4077 unsigned int inldap
;
4081 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
4083 struct discrim_apply_info
{
4084 struct nickserv_discrim
*discrim
;
4085 discrim_search_func func
;
4086 struct userNode
*source
;
4087 unsigned int matched
;
4090 static struct nickserv_discrim
*
4091 nickserv_discrim_create(struct svccmd
*cmd
, struct userNode
*user
, unsigned int argc
, char *argv
[])
4094 struct nickserv_discrim
*discrim
;
4096 discrim
= malloc(sizeof(*discrim
));
4097 memset(discrim
, 0, sizeof(*discrim
));
4098 discrim
->min_level
= 0;
4099 discrim
->max_level
= INT_MAX
;
4100 discrim
->limit
= 50;
4101 discrim
->min_registered
= 0;
4102 discrim
->max_registered
= INT_MAX
;
4103 discrim
->lastseen
= LONG_MAX
;
4104 discrim
->min_karma
= INT_MIN
;
4105 discrim
->max_karma
= INT_MAX
;
4107 discrim
->inldap
= 2;
4110 for (i
=0; i
<argc
; i
++) {
4111 if (i
== argc
- 1) {
4112 reply("MSG_MISSING_PARAMS", argv
[i
]);
4115 if (!irccasecmp(argv
[i
], "limit")) {
4116 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
4117 } else if (!irccasecmp(argv
[i
], "flags")) {
4118 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
4119 } else if (!irccasecmp(argv
[i
], "registered")) {
4120 const char *cmp
= argv
[++i
];
4121 if (cmp
[0] == '<') {
4122 if (cmp
[1] == '=') {
4123 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
4125 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
4127 } else if (cmp
[0] == '=') {
4128 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
4129 } else if (cmp
[0] == '>') {
4130 if (cmp
[1] == '=') {
4131 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
4133 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
4136 reply("MSG_INVALID_CRITERIA", cmp
);
4138 } else if (!irccasecmp(argv
[i
], "seen")) {
4139 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
4140 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
4141 discrim
->nickmask
= argv
[++i
];
4142 } else if (!irccasecmp(argv
[i
], "hostmask")) {
4144 if (!irccasecmp(argv
[i
], "exact")) {
4145 if (i
== argc
- 1) {
4146 reply("MSG_MISSING_PARAMS", argv
[i
]);
4149 discrim
->hostmask_type
= EXACT
;
4150 } else if (!irccasecmp(argv
[i
], "subset")) {
4151 if (i
== argc
- 1) {
4152 reply("MSG_MISSING_PARAMS", argv
[i
]);
4155 discrim
->hostmask_type
= SUBSET
;
4156 } else if (!irccasecmp(argv
[i
], "superset")) {
4157 if (i
== argc
- 1) {
4158 reply("MSG_MISSING_PARAMS", argv
[i
]);
4161 discrim
->hostmask_type
= SUPERSET
;
4162 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
4163 if (i
== argc
- 1) {
4164 reply("MSG_MISSING_PARAMS", argv
[i
]);
4167 discrim
->hostmask_type
= LASTQUIT
;
4170 discrim
->hostmask_type
= SUPERSET
;
4172 discrim
->hostmask
= argv
[++i
];
4173 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask") || !irccasecmp(argv
[i
], "account")) {
4174 if (!irccasecmp(argv
[++i
], "*")) {
4175 discrim
->handlemask
= 0;
4177 discrim
->handlemask
= argv
[i
];
4179 } else if (!irccasecmp(argv
[i
], "email")) {
4180 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
4181 reply("MSG_NO_SEARCH_ACCESS", "email");
4183 } else if (!irccasecmp(argv
[++i
], "*")) {
4184 discrim
->emailmask
= 0;
4186 discrim
->emailmask
= argv
[i
];
4188 } else if (!irccasecmp(argv
[i
], "access")) {
4189 const char *cmp
= argv
[++i
];
4190 if (cmp
[0] == '<') {
4191 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
4192 if (cmp
[1] == '=') {
4193 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
4195 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
4197 } else if (cmp
[0] == '=') {
4198 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
4199 } else if (cmp
[0] == '>') {
4200 if (cmp
[1] == '=') {
4201 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
4203 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
4206 reply("MSG_INVALID_CRITERIA", cmp
);
4208 } else if (!irccasecmp(argv
[i
], "karma")) {
4209 const char *cmp
= argv
[++i
];
4210 if (cmp
[0] == '<') {
4211 if (cmp
[1] == '=') {
4212 discrim
->max_karma
= strtoul(cmp
+2, NULL
, 0);
4214 discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0) - 1;
4216 } else if (cmp
[0] == '=') {
4217 discrim
->min_karma
= discrim
->max_karma
= strtoul(cmp
+1, NULL
, 0);
4218 } else if (cmp
[0] == '>') {
4219 if (cmp
[1] == '=') {
4220 discrim
->min_karma
= strtoul(cmp
+2, NULL
, 0);
4222 discrim
->min_karma
= strtoul(cmp
+1, NULL
, 0) + 1;
4225 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
4228 } else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[i
], "inldap")) {
4230 if(true_string(argv
[i
])) {
4231 discrim
->inldap
= 1;
4233 else if (false_string(argv
[i
])) {
4234 discrim
->inldap
= 0;
4237 reply("MSG_INVALID_BINARY", argv
[i
]);
4241 reply("MSG_INVALID_CRITERIA", argv
[i
]);
4252 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
4254 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
4255 || (discrim
->flags_off
& hi
->flags
)
4256 || (discrim
->min_registered
> hi
->registered
)
4257 || (discrim
->max_registered
< hi
->registered
)
4258 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
4259 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
4260 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
4261 || (discrim
->min_level
> hi
->opserv_level
)
4262 || (discrim
->max_level
< hi
->opserv_level
)
4263 || (discrim
->min_karma
> hi
->karma
)
4264 || (discrim
->max_karma
< hi
->karma
)
4268 if (discrim
->hostmask
) {
4270 for (i
=0; i
<hi
->masks
->used
; i
++) {
4271 const char *mask
= hi
->masks
->list
[i
];
4272 if ((discrim
->hostmask_type
== SUBSET
)
4273 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
4274 else if ((discrim
->hostmask_type
== EXACT
)
4275 && !irccasecmp(discrim
->hostmask
, mask
)) break;
4276 else if ((discrim
->hostmask_type
== SUPERSET
)
4277 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
4278 else if ((discrim
->hostmask_type
== LASTQUIT
)
4279 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
4281 if (i
==hi
->masks
->used
) return 0;
4283 if (discrim
->nickmask
) {
4284 struct nick_info
*nick
= hi
->nicks
;
4286 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
4289 if (!nick
) return 0;
4292 if(nickserv_conf
.ldap_enable
&& discrim
->inldap
!= 2) {
4294 rc
= ldap_get_user_info(hi
->handle
, NULL
);
4295 if(discrim
->inldap
== 1 && rc
!= LDAP_SUCCESS
)
4297 if(discrim
->inldap
== 0 && rc
== LDAP_SUCCESS
)
4306 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
4308 dict_iterator_t it
, next
;
4309 unsigned int matched
;
4311 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
4312 it
&& (matched
< discrim
->limit
);
4314 next
= iter_next(it
);
4315 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
4316 dsf(source
, iter_data(it
));
4324 search_print_func(struct userNode
*source
, struct handle_info
*match
)
4326 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
4330 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
4335 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
4337 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
4338 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
4343 search_add2ldap_func (struct userNode
*source
, struct handle_info
*match
)
4346 if(match
->email_addr
&& match
->passwd
&& match
->handle
) {
4347 rc
= ldap_do_add(match
->handle
, match
->passwd
, match
->email_addr
);
4348 if(rc
!= LDAP_SUCCESS
) {
4349 send_message(source
, nickserv
, "NSMSG_LDAP_FAIL_ADD", match
->handle
, ldap_err2string(rc
));
4356 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
4358 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
4359 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
4360 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
4361 return hi_b
->opserv_level
- hi_a
->opserv_level
;
4362 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
4366 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
4368 struct handle_info_list hil
;
4369 struct helpfile_table tbl
;
4374 memset(&hil
, 0, sizeof(hil
));
4375 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
4376 struct handle_info
*hi
= iter_data(it
);
4377 if (hi
->opserv_level
)
4378 handle_info_list_append(&hil
, hi
);
4380 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
4381 tbl
.length
= hil
.used
+ 1;
4383 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
4384 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
4385 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4388 for (ii
= 0; ii
< hil
.used
; ) {
4389 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
4390 ary
[0] = hil
.list
[ii
]->handle
;
4391 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
4392 tbl
.contents
[++ii
] = ary
;
4394 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
4395 /*reply("MSG_MATCH_COUNT", hil.used); */
4396 for (ii
= 0; ii
< hil
.used
; ii
++)
4397 free(tbl
.contents
[ii
]);
4402 static NICKSERV_FUNC(cmd_search
)
4404 struct nickserv_discrim
*discrim
;
4405 discrim_search_func action
;
4406 struct svccmd
*subcmd
;
4407 unsigned int matches
;
4410 NICKSERV_MIN_PARMS(3);
4411 sprintf(buf
, "search %s", argv
[1]);
4412 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
4413 if (!irccasecmp(argv
[1], "print"))
4414 action
= search_print_func
;
4415 else if (!irccasecmp(argv
[1], "count"))
4416 action
= search_count_func
;
4417 else if (!irccasecmp(argv
[1], "unregister"))
4418 action
= search_unregister_func
;
4420 else if (nickserv_conf
.ldap_enable
&& !irccasecmp(argv
[1], "add2ldap"))
4421 action
= search_add2ldap_func
;
4424 reply("NSMSG_INVALID_ACTION", argv
[1]);
4428 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
4431 discrim
= nickserv_discrim_create(cmd
, user
, argc
-2, argv
+2);
4435 if (action
== search_print_func
)
4436 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4437 else if (action
== search_count_func
)
4438 discrim
->limit
= INT_MAX
;
4440 matches
= nickserv_discrim_search(discrim
, action
, user
);
4443 reply("MSG_MATCH_COUNT", matches
);
4445 reply("MSG_NO_MATCHES");
4451 static MODCMD_FUNC(cmd_checkpass
)
4453 struct handle_info
*hi
;
4455 NICKSERV_MIN_PARMS(3);
4456 if (!(hi
= get_handle_info(argv
[1]))) {
4457 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
4460 if (checkpass(argv
[2], hi
->passwd
))
4461 reply("CHECKPASS_YES");
4463 reply("CHECKPASS_NO");
4468 static MODCMD_FUNC(cmd_checkemail
)
4470 struct handle_info
*hi
;
4472 NICKSERV_MIN_PARMS(3);
4473 if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
4476 if (!hi
->email_addr
)
4477 reply("CHECKEMAIL_NOT_SET");
4478 else if (!irccasecmp(argv
[2], hi
->email_addr
))
4479 reply("CHECKEMAIL_YES");
4481 reply("CHECKEMAIL_NO");
4486 nickserv_db_read_handle(char *handle
, dict_t obj
)
4489 struct string_list
*masks
, *slist
, *ignores
;
4490 struct handle_info
*hi
;
4491 struct userNode
*authed_users
;
4492 struct userData
*channel_list
;
4493 unsigned long int id
;
4496 char *setter
, *note
;
4499 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
4500 id
= str
? strtoul(str
, NULL
, 0) : 0;
4501 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
4503 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
4506 if ((hi
= get_handle_info(handle
))) {
4507 authed_users
= hi
->users
;
4508 channel_list
= hi
->channels
;
4510 hi
->channels
= NULL
;
4511 dict_remove(nickserv_handle_dict
, hi
->handle
);
4513 authed_users
= NULL
;
4514 channel_list
= NULL
;
4516 if(nickserv_conf
.force_handles_lowercase
)
4517 irc_strtolower(handle
);
4518 hi
= register_handle(handle
, str
, id
);
4520 hi
->users
= authed_users
;
4521 while (authed_users
) {
4522 authed_users
->handle_info
= hi
;
4523 authed_users
= authed_users
->next_authed
;
4526 hi
->channels
= channel_list
;
4527 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
4528 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
4529 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
4530 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
4531 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
4532 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
4533 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
4534 hi
->language
= language_find(str
? str
: "C");
4535 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
4536 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
4537 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
4539 hi
->infoline
= strdup(str
);
4540 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
4541 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4542 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
4543 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
4544 str
= database_get_data(obj
, KEY_KARMA
, RECDB_QSTRING
);
4545 hi
->karma
= str
? strtoul(str
, NULL
, 0) : 0;
4546 /* We want to read the nicks even if disable_nicks is set. This is so
4547 * that we don't lose the nick data entirely. */
4548 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
4550 for (ii
=0; ii
<slist
->used
; ii
++)
4551 register_nick(slist
->list
[ii
], hi
);
4553 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
4555 for (ii
=0; str
[ii
]; ii
++)
4556 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
4558 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
4559 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4560 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
4561 hi
->announcements
= str
? str
[0] : '?';
4562 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
4563 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
4564 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
4565 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
4566 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
4568 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
4570 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
4571 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
4573 nickserv_set_email_addr(hi
, str
);
4574 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
4576 hi
->epithet
= strdup(str
);
4577 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
4579 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
4580 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
4581 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
4582 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
4583 if (setter
&& date
&& note
)
4585 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
4590 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
4592 hi
->fakehost
= strdup(str
);
4594 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
4596 const char *data
, *type
, *expires
, *cookie_str
;
4597 struct handle_cookie
*cookie
;
4599 cookie
= calloc(1, sizeof(*cookie
));
4600 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
4601 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
4602 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
4603 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
4604 if (!type
|| !expires
|| !cookie_str
) {
4605 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
4608 if (!irccasecmp(type
, KEY_ACTIVATION
))
4609 cookie
->type
= ACTIVATION
;
4610 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
4611 cookie
->type
= PASSWORD_CHANGE
;
4612 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
4613 cookie
->type
= EMAIL_CHANGE
;
4614 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
4615 cookie
->type
= ALLOWAUTH
;
4617 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
4620 cookie
->expires
= strtoul(expires
, NULL
, 0);
4621 if (cookie
->expires
< now
)
4624 cookie
->data
= strdup(data
);
4625 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
4629 nickserv_bake_cookie(cookie
);
4631 nickserv_free_cookie(cookie
);
4636 nickserv_saxdb_read(dict_t db
) {
4638 struct record_data
*rd
;
4641 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
4643 handle
= strdup(iter_key(it
));
4644 nickserv_db_read_handle(handle
, rd
->d
.object
);
4650 static NICKSERV_FUNC(cmd_mergedb
)
4652 struct timeval start
, stop
;
4655 NICKSERV_MIN_PARMS(2);
4656 gettimeofday(&start
, NULL
);
4657 if (!(db
= parse_database(argv
[1]))) {
4658 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4661 nickserv_saxdb_read(db
);
4663 gettimeofday(&stop
, NULL
);
4664 stop
.tv_sec
-= start
.tv_sec
;
4665 stop
.tv_usec
-= start
.tv_usec
;
4666 if (stop
.tv_usec
< 0) {
4668 stop
.tv_usec
+= 1000000;
4670 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4675 expire_handles(UNUSED_ARG(void *data
))
4677 dict_iterator_t it
, next
;
4679 struct handle_info
*hi
;
4681 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4682 next
= iter_next(it
);
4684 if ((hi
->opserv_level
> 0)
4686 || HANDLE_FLAGGED(hi
, FROZEN
)
4687 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4690 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4691 if ((now
- hi
->lastseen
) > expiry
) {
4692 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4693 nickserv_unregister_handle(hi
, NULL
, NULL
);
4697 if (nickserv_conf
.handle_expire_frequency
)
4698 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4702 nickserv_load_dict(const char *fname
)
4706 if (!(file
= fopen(fname
, "r"))) {
4707 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4710 while (fgets(line
, sizeof(line
), file
)) {
4713 if (line
[strlen(line
)-1] == '\n')
4714 line
[strlen(line
)-1] = 0;
4715 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4718 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4721 static enum reclaim_action
4722 reclaim_action_from_string(const char *str
) {
4724 return RECLAIM_NONE
;
4725 else if (!irccasecmp(str
, "warn"))
4726 return RECLAIM_WARN
;
4727 else if (!irccasecmp(str
, "svsnick"))
4728 return RECLAIM_SVSNICK
;
4729 else if (!irccasecmp(str
, "kill"))
4730 return RECLAIM_KILL
;
4732 return RECLAIM_NONE
;
4736 nickserv_conf_read(void)
4738 dict_t conf_node
, child
;
4741 struct string_list
*strlist
;
4743 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4744 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4747 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4749 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4750 if (nickserv_conf
.valid_handle_regex_set
)
4751 regfree(&nickserv_conf
.valid_handle_regex
);
4753 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4754 nickserv_conf
.valid_handle_regex_set
= !err
;
4755 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4757 nickserv_conf
.valid_handle_regex_set
= 0;
4759 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4760 if (nickserv_conf
.valid_nick_regex_set
)
4761 regfree(&nickserv_conf
.valid_nick_regex
);
4763 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4764 nickserv_conf
.valid_nick_regex_set
= !err
;
4765 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4767 nickserv_conf
.valid_nick_regex_set
= 0;
4769 str
= database_get_data(conf_node
, KEY_VALID_FAKEHOST_REGEX
, RECDB_QSTRING
);
4770 if (nickserv_conf
.valid_fakehost_regex_set
)
4771 regfree(&nickserv_conf
.valid_fakehost_regex
);
4773 int err
= regcomp(&nickserv_conf
.valid_fakehost_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4774 nickserv_conf
.valid_fakehost_regex_set
= !err
;
4775 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_fakehost_regex (error %d)", err
);
4777 nickserv_conf
.valid_fakehost_regex_set
= 0;
4779 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4781 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4782 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4783 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4784 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4785 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4786 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4787 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4788 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4789 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4790 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4791 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4792 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4793 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4794 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4795 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4796 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4797 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4798 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4799 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4800 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4801 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4802 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4803 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4804 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4805 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4807 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4808 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4809 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4811 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4812 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4813 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4815 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4816 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4817 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4818 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4819 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4820 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4821 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4822 str
= database_get_data(conf_node
, KEY_OUNREGISTER_INACTIVE
, RECDB_QSTRING
);
4823 nickserv_conf
.ounregister_inactive
= str
? ParseInterval(str
) : 86400*28;
4824 str
= database_get_data(conf_node
, KEY_OUNREGISTER_FLAGS
, RECDB_QSTRING
);
4827 nickserv_conf
.ounregister_flags
= 0;
4829 unsigned int pos
= handle_inverse_flags
[(unsigned char)*str
];
4832 nickserv_conf
.ounregister_flags
|= 1 << (pos
- 1);
4834 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4835 if (!nickserv_conf
.disable_nicks
) {
4836 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4837 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4838 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4839 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4840 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4841 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4842 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4843 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4845 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4846 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4847 const char *key
= iter_key(it
), *value
;
4851 if (!strncasecmp(key
, "uc_", 3))
4852 flag
= toupper(key
[3]);
4853 else if (!strncasecmp(key
, "lc_", 3))
4854 flag
= tolower(key
[3]);
4858 if ((pos
= handle_inverse_flags
[flag
])) {
4859 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4860 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4863 if (nickserv_conf
.weak_password_dict
)
4864 dict_delete(nickserv_conf
.weak_password_dict
);
4865 nickserv_conf
.weak_password_dict
= dict_new();
4866 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4867 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4868 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4869 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4871 nickserv_load_dict(str
);
4872 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4873 if (nickserv
&& str
)
4874 NickChange(nickserv
, str
, 0);
4875 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4876 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4877 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4878 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4879 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4880 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4881 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4882 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4883 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4884 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4885 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4886 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4887 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4888 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4889 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4890 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4891 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4892 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4893 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4894 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4896 free_string_list(nickserv_conf
.denied_fakehost_words
);
4897 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4899 strlist
= string_list_copy(strlist
);
4901 strlist
= alloc_string_list(4);
4902 string_list_append(strlist
, strdup("sex"));
4903 string_list_append(strlist
, strdup("fuck"));
4905 nickserv_conf
.denied_fakehost_words
= strlist
;
4907 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4908 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4910 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4911 nickserv_conf
.auto_oper
= str
? str
: "";
4913 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4914 nickserv_conf
.auto_admin
= str
? str
: "";
4916 str
= database_get_data(conf_node
, KEY_AUTO_OPER_PRIVS
, RECDB_QSTRING
);
4917 nickserv_conf
.auto_oper_privs
= str
? str
: "";
4919 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN_PRIVS
, RECDB_QSTRING
);
4920 nickserv_conf
.auto_admin_privs
= str
? str
: "";
4922 str
= conf_get_data("server/network", RECDB_QSTRING
);
4923 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4924 if (!nickserv_conf
.auth_policer_params
) {
4925 nickserv_conf
.auth_policer_params
= policer_params_new();
4926 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4927 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4929 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4930 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4931 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4933 str
= database_get_data(conf_node
, KEY_LDAP_ENABLE
, RECDB_QSTRING
);
4934 nickserv_conf
.ldap_enable
= str
? strtoul(str
, NULL
, 0) : 0;
4936 str
= database_get_data(conf_node
, KEY_FORCE_HANDLES_LOWERCASE
, RECDB_QSTRING
);
4937 nickserv_conf
.force_handles_lowercase
= str
? strtol(str
, NULL
, 0) : 0;
4940 if(nickserv_conf
.ldap_enable
> 0) {
4941 /* ldap is enabled but not compiled in - error out */
4942 log_module(MAIN_LOG
, LOG_ERROR
, "ldap is enabled in config, but not compiled in!");
4943 nickserv_conf
.ldap_enable
= 0;
4949 str
= database_get_data(conf_node
, KEY_LDAP_URI
, RECDB_QSTRING
);
4950 nickserv_conf
.ldap_uri
= str
? str
: "";
4952 str
= database_get_data(conf_node
, KEY_LDAP_BASE
, RECDB_QSTRING
);
4953 nickserv_conf
.ldap_base
= str
? str
: "";
4955 str
= database_get_data(conf_node
, KEY_LDAP_DN_FMT
, RECDB_QSTRING
);
4956 nickserv_conf
.ldap_dn_fmt
= str
? str
: "";
4958 str
= database_get_data(conf_node
, KEY_LDAP_VERSION
, RECDB_QSTRING
);
4959 nickserv_conf
.ldap_version
= str
? strtoul(str
, NULL
, 0) : 3;
4961 str
= database_get_data(conf_node
, KEY_LDAP_AUTOCREATE
, RECDB_QSTRING
);
4962 nickserv_conf
.ldap_autocreate
= str
? strtoul(str
, NULL
, 0) : 0;
4964 str
= database_get_data(conf_node
, KEY_LDAP_TIMEOUT
, RECDB_QSTRING
);
4965 nickserv_conf
.ldap_timeout
= str
? strtoul(str
, NULL
, 0) : 5;
4967 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_DN
, RECDB_QSTRING
);
4968 nickserv_conf
.ldap_admin_dn
= str
? str
: "";
4970 str
= database_get_data(conf_node
, KEY_LDAP_ADMIN_PASS
, RECDB_QSTRING
);
4971 nickserv_conf
.ldap_admin_pass
= str
? str
: "";
4973 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_ACCOUNT
, RECDB_QSTRING
);
4974 nickserv_conf
.ldap_field_account
= str
? str
: "";
4976 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_PASSWORD
, RECDB_QSTRING
);
4977 nickserv_conf
.ldap_field_password
= str
? str
: "";
4979 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_EMAIL
, RECDB_QSTRING
);
4980 nickserv_conf
.ldap_field_email
= str
? str
: "";
4982 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_OSLEVEL
, RECDB_QSTRING
);
4983 nickserv_conf
.ldap_field_oslevel
= str
? str
: "";
4985 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_DN
, RECDB_QSTRING
);
4986 nickserv_conf
.ldap_oper_group_dn
= str
? str
: "";
4988 str
= database_get_data(conf_node
, KEY_LDAP_OPER_GROUP_LEVEL
, RECDB_QSTRING
);
4989 nickserv_conf
.ldap_oper_group_level
= str
? strtoul(str
, NULL
, 0) : 99;
4991 str
= database_get_data(conf_node
, KEY_LDAP_FIELD_GROUP_MEMBER
, RECDB_QSTRING
);
4992 nickserv_conf
.ldap_field_group_member
= str
? str
: "";
4994 free_string_list(nickserv_conf
.ldap_object_classes
);
4995 strlist
= database_get_data(conf_node
, KEY_LDAP_OBJECT_CLASSES
, RECDB_STRING_LIST
);
4997 strlist
= string_list_copy(strlist
);
4999 strlist
= alloc_string_list(4);
5000 string_list_append(strlist
, strdup("top"));
5002 nickserv_conf
.ldap_object_classes
= strlist
;
5009 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
5011 char newnick
[NICKLEN
+1];
5020 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
5021 send_message(user
, nickserv
, "NSMSG_RECLAIM_HOWTO", ni
->owner
->handle
, nickserv
->nick
, self
->name
, ni
->owner
->handle
);
5023 case RECLAIM_SVSNICK
:
5025 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
5026 } while (GetUserH(newnick
));
5027 irc_svsnick(nickserv
, user
, newnick
);
5030 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
5031 DelUser(user
, nickserv
, 1, msg
);
5037 nickserv_reclaim_p(void *data
) {
5038 struct userNode
*user
= data
;
5039 struct nick_info
*ni
= get_nick_info(user
->nick
);
5041 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5045 check_user_nick(struct userNode
*user
, UNUSED_ARG(void *extra
)) {
5046 struct nick_info
*ni
;
5047 user
->modes
&= ~FLAGS_REGNICK
;
5048 if (!(ni
= get_nick_info(user
->nick
)))
5050 if (user
->handle_info
== ni
->owner
) {
5051 user
->modes
|= FLAGS_REGNICK
;
5055 if (nickserv_conf
.warn_nick_owned
)
5056 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
5057 send_message(user
, nickserv
, "NSMSG_RECLAIM_HOWTO", ni
->owner
->handle
, nickserv
->nick
, self
->name
, ni
->owner
->handle
);
5058 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
5060 if (nickserv_conf
.auto_reclaim_delay
)
5061 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
5063 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
5069 handle_account(struct userNode
*user
, const char *stamp
)
5071 struct handle_info
*hi
;
5074 #ifdef WITH_PROTOCOL_P10
5075 time_t timestamp
= 0;
5077 colon
= strchr(stamp
, ':');
5078 if(colon
&& colon
[1])
5081 timestamp
= atoi(colon
+1);
5083 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
5084 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
5086 log_module(MAIN_LOG
, LOG_WARNING
, "%s using account %s but timestamp does not match %s is not %s.", user
->nick
, stamp
, ctime(×tamp
),
5087 ctime(&hi
->registered
));
5091 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
5092 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
5096 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
5099 set_user_handle_info(user
, hi
, 0);
5101 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
5106 handle_nick_change(struct userNode
*user
, const char *old_nick
, UNUSED_ARG(void *extra
))
5108 struct handle_info
*hi
;
5110 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
5111 dict_remove(nickserv_allow_auth_dict
, old_nick
);
5112 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
5114 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5115 check_user_nick(user
, NULL
);
5119 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
), UNUSED_ARG(void *extra
))
5121 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
5122 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
5123 set_user_handle_info(user
, NULL
, 0);
5126 static struct modcmd
*
5127 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
5129 if (min_level
> 0) {
5131 sprintf(buf
, "%u", min_level
);
5132 if (must_be_qualified
) {
5133 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
5135 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
5137 } else if (min_level
== 0) {
5138 if (must_be_qualified
) {
5139 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5141 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
5144 if (must_be_qualified
) {
5145 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
5147 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
5153 nickserv_db_cleanup(void)
5155 unreg_del_user_func(nickserv_remove_user
, NULL
);
5156 userList_clean(&curr_helpers
);
5157 policer_params_delete(nickserv_conf
.auth_policer_params
);
5158 dict_delete(nickserv_handle_dict
);
5159 dict_delete(nickserv_nick_dict
);
5160 dict_delete(nickserv_opt_dict
);
5161 dict_delete(nickserv_allow_auth_dict
);
5162 dict_delete(nickserv_email_dict
);
5163 dict_delete(nickserv_id_dict
);
5164 dict_delete(nickserv_conf
.weak_password_dict
);
5165 free(auth_func_list
);
5166 free(unreg_func_list
);
5168 free(rf_list_extra
);
5169 free(allowauth_func_list
);
5170 free(allowauth_func_list_extra
);
5171 free(handle_merge_func_list
);
5172 free(handle_merge_func_list_extra
);
5173 free(failpw_func_list
);
5174 free(failpw_func_list_extra
);
5175 if (nickserv_conf
.valid_handle_regex_set
)
5176 regfree(&nickserv_conf
.valid_handle_regex
);
5177 if (nickserv_conf
.valid_nick_regex_set
)
5178 regfree(&nickserv_conf
.valid_nick_regex
);
5181 void handle_loc_auth_oper(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
)) {
5182 if (!*nickserv_conf
.auto_oper
|| !user
->handle_info
)
5185 if (!IsOper(user
)) {
5186 if (*nickserv_conf
.auto_admin
&& user
->handle_info
->opserv_level
>= opserv_conf_admin_level()) {
5187 irc_umode(user
, nickserv_conf
.auto_admin
);
5188 irc_sno(0x1, "%s (%s@%s) is now an IRC Administrator",
5189 user
->nick
, user
->ident
, user
->hostname
);
5190 } else if (*nickserv_conf
.auto_oper
&& user
->handle_info
->opserv_level
) {
5191 irc_umode(user
, nickserv_conf
.auto_oper
);
5192 irc_sno(0x1, "%s (%s@%s) is now an IRC Operator",
5193 user
->nick
, user
->ident
, user
->hostname
);
5199 init_nickserv(const char *nick
)
5201 struct chanNode
*chan
;
5203 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
5204 reg_new_user_func(check_user_nick
, NULL
);
5205 reg_nick_change_func(handle_nick_change
, NULL
);
5206 reg_del_user_func(nickserv_remove_user
, NULL
);
5207 reg_account_func(handle_account
);
5208 reg_auth_func(handle_loc_auth_oper
);
5210 /* set up handle_inverse_flags */
5211 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
5212 for (i
=0; handle_flags
[i
]; i
++) {
5213 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
5214 flag_access_levels
[i
] = 0;
5217 conf_register_reload(nickserv_conf_read
);
5218 nickserv_opt_dict
= dict_new();
5219 nickserv_email_dict
= dict_new();
5221 dict_set_free_keys(nickserv_email_dict
, free
);
5222 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
5224 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
5225 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
5226 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
5227 * a big pain to disable since its nolonger in the config file. ) -Rubin
5229 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
5230 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
5231 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
5232 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
5233 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
5234 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
5235 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
5236 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
5237 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
5238 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
5239 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
5240 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
5241 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
5242 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
5243 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
5244 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
5245 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
5246 nickserv_define_func("MERGE", cmd_merge
, 750, 1, 0);
5247 if (!nickserv_conf
.disable_nicks
) {
5248 /* nick management commands */
5249 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
5250 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
5251 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
5252 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
5253 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
5254 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
5256 if (nickserv_conf
.email_enabled
) {
5257 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
5258 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
5259 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
5260 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
5261 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
5262 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
5264 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
5265 /* ignore commands */
5266 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
5267 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
5268 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
5269 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
5270 /* miscellaneous commands */
5271 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
5272 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
5273 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
5274 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
5275 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
5276 nickserv_define_func("CHECKEMAIL", cmd_checkemail
, 0, 1, 0);
5278 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
5279 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
5280 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
5281 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
5282 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
5283 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
5284 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
5285 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
5286 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
5287 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
5288 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
5289 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
5290 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
5291 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
5292 if (nickserv_conf
.titlehost_suffix
) {
5293 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
5294 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
5296 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
5297 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
5298 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
5299 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
5300 dict_insert(nickserv_opt_dict
, "KARMA", opt_karma
);
5302 nickserv_handle_dict
= dict_new();
5303 dict_set_free_keys(nickserv_handle_dict
, free
);
5304 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
5306 nickserv_id_dict
= dict_new();
5307 dict_set_free_keys(nickserv_id_dict
, free
);
5309 nickserv_nick_dict
= dict_new();
5310 dict_set_free_data(nickserv_nick_dict
, free
);
5312 nickserv_allow_auth_dict
= dict_new();
5314 userList_init(&curr_helpers
);
5317 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
5318 nickserv
= AddLocalUser(nick
, nick
, NULL
, "Nick Services", modes
);
5319 nickserv_service
= service_register(nickserv
);
5321 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
5322 reg_exit_func(nickserv_db_cleanup
);
5323 if(nickserv_conf
.handle_expire_frequency
)
5324 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
5326 if(autojoin_channels
&& nickserv
) {
5327 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
5328 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
5329 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
5333 ldap_do_init(nickserv_conf
);
5336 message_register_table(msgtab
);