]> jfr.im git - irc/evilnet/x3.git/blob - src/nickserv.c
Added support for SSL fingerprint authentication
[irc/evilnet/x3.git] / src / nickserv.c
1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
3 *
4 * This file is part of x3.
5 *
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.
10 *
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.
15 *
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.
19 */
20
21 #include "chanserv.h"
22 #include "conf.h"
23 #include "config.h"
24 #include "global.h"
25 #include "modcmd.h"
26 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
27 #include "saxdb.h"
28 #include "mail.h"
29 #include "timeq.h"
30 #include "x3ldap.h"
31
32 #include <tre/regex.h>
33
34 #ifdef WITH_LDAP
35 #include <ldap.h>
36 #endif
37
38 #define NICKSERV_CONF_NAME "services/nickserv"
39
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"
86
87 #define KEY_ID "id"
88 #define KEY_PASSWD "passwd"
89 #define KEY_NICKS "nicks"
90 #define KEY_MASKS "masks"
91 #define KEY_SSLFPS "sslfps"
92 #define KEY_IGNORES "ignores"
93 #define KEY_OPSERV_LEVEL "opserv_level"
94 #define KEY_FLAGS "flags"
95 #define KEY_REGISTER_ON "register"
96 #define KEY_LAST_SEEN "lastseen"
97 #define KEY_INFO "info"
98 #define KEY_USERLIST_STYLE "user_style"
99 #define KEY_SCREEN_WIDTH "screen_width"
100 #define KEY_LAST_AUTHED_HOST "last_authed_host"
101 #define KEY_LAST_QUIT_HOST "last_quit_host"
102 #define KEY_EMAIL_ADDR "email_addr"
103 #define KEY_COOKIE "cookie"
104 #define KEY_COOKIE_DATA "data"
105 #define KEY_COOKIE_TYPE "type"
106 #define KEY_COOKIE_EXPIRES "expires"
107 #define KEY_ACTIVATION "activation"
108 #define KEY_PASSWORD_CHANGE "password change"
109 #define KEY_EMAIL_CHANGE "email change"
110 #define KEY_ALLOWAUTH "allowauth"
111 #define KEY_EPITHET "epithet"
112 #define KEY_TABLE_WIDTH "table_width"
113 #define KEY_ANNOUNCEMENTS "announcements"
114 #define KEY_MAXLOGINS "maxlogins"
115 #define KEY_FAKEHOST "fakehost"
116 #define KEY_NOTE_NOTE "note"
117 #define KEY_NOTE_SETTER "setter"
118 #define KEY_NOTE_DATE "date"
119 #define KEY_KARMA "karma"
120 #define KEY_FORCE_HANDLES_LOWERCASE "force_handles_lowercase"
121
122 #define KEY_LDAP_ENABLE "ldap_enable"
123
124 #ifdef WITH_LDAP
125 #define KEY_LDAP_URI "ldap_uri"
126 #define KEY_LDAP_BASE "ldap_base"
127 #define KEY_LDAP_DN_FMT "ldap_dn_fmt"
128 #define KEY_LDAP_VERSION "ldap_version"
129 #define KEY_LDAP_AUTOCREATE "ldap_autocreate"
130 #define KEY_LDAP_ADMIN_DN "ldap_admin_dn"
131 #define KEY_LDAP_ADMIN_PASS "ldap_admin_pass"
132 #define KEY_LDAP_FIELD_ACCOUNT "ldap_field_account"
133 #define KEY_LDAP_FIELD_PASSWORD "ldap_field_password"
134 #define KEY_LDAP_FIELD_EMAIL "ldap_field_email"
135 #define KEY_LDAP_FIELD_OSLEVEL "ldap_field_oslevel"
136 #define KEY_LDAP_OBJECT_CLASSES "ldap_object_classes"
137 #define KEY_LDAP_OPER_GROUP_DN "ldap_oper_group_dn"
138 #define KEY_LDAP_OPER_GROUP_LEVEL "ldap_oper_group_level"
139 #define KEY_LDAP_FIELD_GROUP_MEMBER "ldap_field_group_member"
140 #define KEY_LDAP_TIMEOUT "ldap_timeout"
141 #endif
142
143 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
144
145 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
146 #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[])
147 typedef OPTION_FUNC(option_func_t);
148
149 DEFINE_LIST(handle_info_list, struct handle_info*)
150
151 #define NICKSERV_MIN_PARMS(N) do { \
152 if (argc < N) { \
153 reply("MSG_MISSING_PARAMS", argv[0]); \
154 svccmd_send_help_brief(user, nickserv, cmd); \
155 return 0; \
156 } } while (0)
157
158 struct userNode *nickserv;
159 struct userList curr_helpers;
160 const char *handle_flags = HANDLE_FLAGS;
161
162 extern struct string_list *autojoin_channels;
163 static struct module *nickserv_module;
164 static struct service *nickserv_service;
165 static struct log_type *NS_LOG;
166 dict_t nickserv_handle_dict; /* contains struct handle_info* */
167 static dict_t nickserv_id_dict; /* contains struct handle_info* */
168 static dict_t nickserv_nick_dict; /* contains struct nick_info* */
169 static dict_t nickserv_opt_dict; /* contains option_func_t* */
170 static dict_t nickserv_allow_auth_dict; /* contains struct handle_info* */
171 static dict_t nickserv_email_dict; /* contains struct handle_info_list*, indexed by email addr */
172 static char handle_inverse_flags[256];
173 static unsigned int flag_access_levels[32];
174 static const struct message_entry msgtab[] = {
175 { "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." },
176 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
177 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu characters or less."},
178 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
179 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
180 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
181 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
182 { "NSMSG_LDAP_FAIL", "There was a problem in contacting the account server (ldap): %s. Please try again later." },
183 { "NSMSG_LDAP_FAIL_ADD", "There was a problem in adding account %s to ldap: %s." },
184 { "NSMSG_LDAP_FAIL_SEND_EMAIL", "There was a problem in storing your email address in the account server (ldap): %s. Please try again later." },
185 { "NSMSG_LDAP_FAIL_GET_EMAIL", "There was a problem in retrieving your email address from the account server (ldap): %s. Please try again later." },
186 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
187 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
188 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
189 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
190 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
191 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
192 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
193 { "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." },
194 { "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." },
195 { "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." },
196 { "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." },
197 { "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." },
198 { "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." },
199 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
200 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
201 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
202 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
203 { "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." },
204 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
205 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
206 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
207 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
208 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
209 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
210 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
211 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
212 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
213 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
214 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
215 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
216 { "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 *@*)." },
217 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
218 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
219 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
220 { "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)" },
221 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
222 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
223 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
224 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
225 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
226 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
227 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
228 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
229 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
230 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
231 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
232 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
233 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
234 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
235 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
236 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
237 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
238 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
239 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
240 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
241 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
242 { "NSMSG_HANDLEINFO_KARMA", "Karma: %d" },
243 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
244 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
245 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
246 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
247 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
248 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
249 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
250 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
251 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
252 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
253 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
254 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
255 { "NSMSG_INVALID_KARMA", "$b%s$b is not a valid karma modifier." },
256 { "NSMSG_SET_KARMA", "$bKARMA: $b%d$b" },
257 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
258 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
259 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
260 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
261 { "NSMSG_HANDLEINFO_SSLFPS", "SSL Fingerprints(s): %s" },
262 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
263 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
264 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
265 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
266 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
267 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
268 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
269 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
270 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
271 { "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)." },
272 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
273 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
274 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
275 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
276 { "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." },
277 { "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." },
278 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
279 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
280 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
281 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
282 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
283 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
284 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
285 { "NSMSG_PASS_SUCCESS", "Password changed." },
286 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
287 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
288 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
289 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
290 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
291 { "NSMSG_ADDSSLFP_ALREADY", "$b%s$b is already an SSL fingerprint in your account." },
292 { "NSMSG_ADDSSLFP_SUCCESS", "SSL fingerprint %s added." },
293 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
294 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
295 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
296 { "NSMSG_DELSSLFP_SUCCESS", "SSL fingerprint %s deleted." },
297 { "NSMSG_DELSSLFP_NOT_FOUND", "Unable to find SSL fingerprint to be deleted." },
298 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
299 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
300 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
301 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
302 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
303 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
304 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
305 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
306 { "NSMSG_UNREGISTER_MUST_FORCE", "Account $b%s$b is not inactive or has special flags set; use FORCE to unregister it." },
307 { "NSMSG_UNREGISTER_CANNOT_FORCE", "Account $b%s$b is not inactive or has special flags set; have an IRCOp use FORCE to unregister it." },
308 { "NSMSG_UNREGISTER_NODELETE", "Account $b%s$b is protected from unregistration." },
309 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
310 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
311 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
312 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
313 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
314 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
315 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
316 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
317 { "NSMSG_NO_ACCESS", "Access denied." },
318 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
319 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
320 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
321 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
322 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T".%03lu seconds)." },
323 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
324 { "NSMSG_BAD_HANDLE", "Account $b%s$b is not allowed because it is reserved, is too long, or contains invalid characters." },
325 { "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." },
326 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
327 { "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." },
328 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
329 { "NSMSG_SEARCH_MATCH", "Match: %s" },
330 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
331 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
332 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
333 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
334 { "NSMSG_RECLAIM_HOWTO", "To auth to account %s you must use /msg %s@%s AUTH %s <password>" },
335 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
336 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
337 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
338 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
339 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
340 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
341 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
342 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
343 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
344 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
345 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
346 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
347 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
348 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
349 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
350 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
351 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
352 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
353 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
354 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
355 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
356 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
357 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
358 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
359 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
360 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
361 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
362 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
363 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
364 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
365
366 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
367 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
368
369 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
370 { "NSEMAIL_ACTIVATION_BODY",
371 "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"
372 "%2$s\n"
373 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
374 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
375 "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"
376 "/msg %3$s@%4$s AUTH %5$s your-password\n"
377 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
378 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
379 "\n"
380 "If you did NOT request this account, you do not need to do anything.\n"
381 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
382 { "NSEMAIL_ACTIVATION_BODY_WEB",
383 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
384 "%2$s\n"
385 "To verify your email address and complete the account registration, visit the following URL:\n"
386 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
387 "\n"
388 "If you did NOT request this account, you do not need to do anything.\n"
389 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
390 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
391 { "NSEMAIL_PASSWORD_CHANGE_BODY",
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, log on to %1$s and type the following command:\n"
394 "/msg %3$s@%4$s COOKIE %5$s %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_PASSWORD_CHANGE_BODY_WEB",
398 "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"
399 "To complete the password change, click the following URL:\n"
400 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
401 "If you did NOT request your password to be changed, you do not need to do anything.\n"
402 "Please contact the %1$s staff if you have questions." },
403 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
404 #ifdef stupid_verify_old_email
405 { "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." },
406 { "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." },
407 #endif
408 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
409 { "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." },
410 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
411 { "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." },
412 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
413 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
414 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
415 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
416 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
417 { "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." },
418 { "CHECKPASS_YES", "Yes." },
419 { "CHECKPASS_NO", "No." },
420 { "CHECKEMAIL_NOT_SET", "No email set." },
421 { "CHECKEMAIL_YES", "Yes." },
422 { "CHECKEMAIL_NO", "No." },
423 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
424 { NULL, NULL }
425 };
426
427 static void nickserv_reclaim(struct userNode *user, struct nick_info *ni, enum reclaim_action action);
428 static void nickserv_reclaim_p(void *data);
429 static int nickserv_addmask(struct userNode *user, struct handle_info *hi, const char *mask);
430
431 struct nickserv_config nickserv_conf;
432
433 /* We have 2^32 unique account IDs to use. */
434 unsigned long int highest_id = 0;
435
436 static char *
437 canonicalize_hostmask(char *mask)
438 {
439 char *out = mask, *temp;
440 if ((temp = strchr(mask, '!'))) {
441 temp++;
442 while (*temp) *out++ = *temp++;
443 *out++ = 0;
444 }
445 return mask;
446 }
447
448 static struct handle_note *
449 nickserv_add_note(const char *setter, time_t date, const char *text)
450 {
451 struct handle_note *note = calloc(1, sizeof(*note) + strlen(text));
452
453 strncpy(note->setter, setter, sizeof(note->setter)-1);
454 note->date = date;
455 memcpy(note->note, text, strlen(text));
456 return note;
457 }
458
459 static struct handle_info *
460 register_handle(const char *handle, const char *passwd, UNUSED_ARG(unsigned long id))
461 {
462 struct handle_info *hi;
463
464 hi = calloc(1, sizeof(*hi));
465 hi->userlist_style = nickserv_conf.default_style ? nickserv_conf.default_style : HI_DEFAULT_STYLE;
466 hi->announcements = '?';
467 hi->handle = strdup(handle);
468 safestrncpy(hi->passwd, passwd, sizeof(hi->passwd));
469 hi->infoline = NULL;
470 dict_insert(nickserv_handle_dict, hi->handle, hi);
471
472 return hi;
473 }
474
475 static void
476 register_nick(const char *nick, struct handle_info *owner)
477 {
478 struct nick_info *ni;
479 ni = malloc(sizeof(struct nick_info));
480 safestrncpy(ni->nick, nick, sizeof(ni->nick));
481 ni->owner = owner;
482 ni->next = owner->nicks;
483 owner->nicks = ni;
484 dict_insert(nickserv_nick_dict, ni->nick, ni);
485 }
486
487 static void
488 delete_nick(struct nick_info *ni)
489 {
490 struct nick_info *last, *next;
491 struct userNode *user;
492 /* Check to see if we should mark a user as unregistered. */
493 if ((user = GetUserH(ni->nick)) && IsReggedNick(user)) {
494 user->modes &= ~FLAGS_REGNICK;
495 irc_regnick(user);
496 }
497 /* Remove ni from the nick_info linked list. */
498 if (ni == ni->owner->nicks) {
499 ni->owner->nicks = ni->next;
500 } else {
501 last = ni->owner->nicks;
502 next = last->next;
503 while (next != ni) {
504 last = next;
505 next = last->next;
506 }
507 last->next = next->next;
508 }
509 dict_remove(nickserv_nick_dict, ni->nick);
510 }
511
512 static unreg_func_t *unreg_func_list;
513 static void **unreg_func_list_extra;
514 static unsigned int unreg_func_size = 0, unreg_func_used = 0;
515
516 void
517 reg_unreg_func(unreg_func_t func, void *extra)
518 {
519 if (unreg_func_used == unreg_func_size) {
520 if (unreg_func_size) {
521 unreg_func_size <<= 1;
522 unreg_func_list = realloc(unreg_func_list, unreg_func_size*sizeof(unreg_func_t));
523 unreg_func_list_extra = realloc(unreg_func_list_extra, unreg_func_size*sizeof(void*));
524 } else {
525 unreg_func_size = 8;
526 unreg_func_list = malloc(unreg_func_size*sizeof(unreg_func_t));
527 unreg_func_list_extra = malloc(unreg_func_size*sizeof(void*));
528 }
529 }
530 unreg_func_list[unreg_func_used] = func;
531 unreg_func_list_extra[unreg_func_used++] = extra;
532 }
533
534 static void
535 nickserv_free_cookie(void *data)
536 {
537 struct handle_cookie *cookie = data;
538 if (cookie->hi) cookie->hi->cookie = NULL;
539 if (cookie->data) free(cookie->data);
540 free(cookie);
541 }
542
543 static void
544 free_handle_info(void *vhi)
545 {
546 struct handle_info *hi = vhi;
547
548 free_string_list(hi->masks);
549 free_string_list(hi->sslfps);
550 free_string_list(hi->ignores);
551 assert(!hi->users);
552
553 while (hi->nicks)
554 delete_nick(hi->nicks);
555 free(hi->infoline);
556 free(hi->epithet);
557 free(hi->note);
558 free(hi->fakehost);
559 if (hi->cookie) {
560 timeq_del(hi->cookie->expires, nickserv_free_cookie, hi->cookie, 0);
561 nickserv_free_cookie(hi->cookie);
562 }
563 if (hi->email_addr) {
564 struct handle_info_list *hil = dict_find(nickserv_email_dict, hi->email_addr, NULL);
565 handle_info_list_remove(hil, hi);
566 if (!hil->used)
567 dict_remove(nickserv_email_dict, hi->email_addr);
568 }
569 free(hi);
570 }
571
572 static void set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp);
573
574 static int
575 nickserv_unregister_handle(struct handle_info *hi, struct userNode *notify, struct userNode *bot)
576 {
577 unsigned int n;
578 struct userNode *uNode;
579
580 #ifdef WITH_LDAP
581 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
582 int rc;
583 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
584 if( (rc = ldap_delete_account(hi->handle)) != LDAP_SUCCESS) {
585 if(notify) {
586 send_message(notify, bot, "NSMSG_LDAP_FAIL", ldap_err2string(rc));
587 }
588 if(rc != LDAP_NO_SUCH_OBJECT)
589 return false; /* if theres noone there to delete, its kinda ok, right ?:) */
590 }
591 }
592 }
593 #endif
594 for (n=0; n<unreg_func_used; n++)
595 unreg_func_list[n](notify, hi, unreg_func_list_extra[n]);
596 while (hi->users) {
597 if (nickserv_conf.sync_log) {
598 uNode = GetUserH(hi->users->nick);
599 if (uNode)
600 irc_delete(uNode);
601 }
602 set_user_handle_info(hi->users, NULL, 0);
603 }
604 if (notify) {
605 if (nickserv_conf.disable_nicks)
606 send_message(notify, bot, "NSMSG_UNREGISTER_SUCCESS", hi->handle);
607 else
608 send_message(notify, bot, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi->handle);
609 }
610
611 if (nickserv_conf.sync_log)
612 SyncLog("UNREGISTER %s", hi->handle);
613
614 dict_remove(nickserv_handle_dict, hi->handle);
615 return true;
616 }
617
618 struct handle_info*
619 get_handle_info(const char *handle)
620 {
621 return dict_find(nickserv_handle_dict, handle, 0);
622 }
623
624 struct nick_info*
625 get_nick_info(const char *nick)
626 {
627 return nickserv_conf.disable_nicks ? 0 : dict_find(nickserv_nick_dict, nick, 0);
628 }
629
630 struct modeNode *
631 find_handle_in_channel(struct chanNode *channel, struct handle_info *handle, struct userNode *except)
632 {
633 unsigned int nn;
634 struct modeNode *mn;
635
636 for (nn=0; nn<channel->members.used; ++nn) {
637 mn = channel->members.list[nn];
638 if ((mn->user != except) && (mn->user->handle_info == handle))
639 return mn;
640 }
641 return NULL;
642 }
643
644 int
645 oper_has_access(struct userNode *user, struct userNode *bot, unsigned int min_level, unsigned int quiet) {
646 if (!user->handle_info) {
647 if (!quiet)
648 send_message(user, bot, "MSG_AUTHENTICATE");
649 return 0;
650 }
651
652 if (!IsOper(user) && (!IsHelping(user) || min_level)) {
653 if (!quiet)
654 send_message(user, bot, "NSMSG_NO_ACCESS");
655 return 0;
656 }
657
658 if (HANDLE_FLAGGED(user->handle_info, OPER_SUSPENDED)) {
659 if (!quiet)
660 send_message(user, bot, "MSG_OPER_SUSPENDED");
661 return 0;
662 }
663
664 if (user->handle_info->opserv_level < min_level) {
665 if (!quiet)
666 send_message(user, bot, "NSMSG_NO_ACCESS");
667 return 0;
668 }
669
670 return 1;
671 }
672
673 static int
674 is_valid_handle(const char *handle)
675 {
676 struct userNode *user;
677 /* cant register a juped nick/service nick as handle, to prevent confusion */
678 user = GetUserH(handle);
679 if (user && IsLocal(user))
680 return 0;
681 /* check against maximum length */
682 if (strlen(handle) > NICKSERV_HANDLE_LEN)
683 return 0;
684 /* for consistency, only allow account names that could be nicks */
685 if (!is_valid_nick(handle))
686 return 0;
687 /* disallow account names that look like bad words */
688 if (opserv_bad_channel(handle))
689 return 0;
690 /* test either regex or containing all valid chars */
691 if (nickserv_conf.valid_handle_regex_set) {
692 int err = regexec(&nickserv_conf.valid_handle_regex, handle, 0, 0, 0);
693 if (err) {
694 char buff[256];
695 buff[regerror(err, &nickserv_conf.valid_handle_regex, buff, sizeof(buff))] = 0;
696 log_module(NS_LOG, LOG_INFO, "regexec error: %s (%d)", buff, err);
697 }
698 return !err;
699 } else {
700 return !handle[strspn(handle, NICKSERV_VALID_CHARS)];
701 }
702 }
703
704 static int
705 is_registerable_nick(const char *nick)
706 {
707 struct userNode *user;
708 /* cant register a juped nick/service nick as nick, to prevent confusion */
709 user = GetUserH(nick);
710 if (user && IsLocal(user))
711 return 0;
712 /* for consistency, only allow nicks names that could be nicks */
713 if (!is_valid_nick(nick))
714 return 0;
715 /* disallow nicks that look like bad words */
716 if (opserv_bad_channel(nick))
717 return 0;
718 /* check length */
719 if (strlen(nick) > NICKLEN)
720 return 0;
721 /* test either regex or as valid handle */
722 if (nickserv_conf.valid_nick_regex_set) {
723 int err = regexec(&nickserv_conf.valid_nick_regex, nick, 0, 0, 0);
724 if (err) {
725 char buff[256];
726 buff[regerror(err, &nickserv_conf.valid_nick_regex, buff, sizeof(buff))] = 0;
727 log_module(NS_LOG, LOG_INFO, "regexec error: %s (%d)", buff, err);
728 }
729 return !err;
730 }
731 return 1;
732 }
733 /* this has been replaced with one in tools.c
734
735 static int
736 is_valid_email_addr(const char *email)
737 {
738 return strchr(email, '@') != NULL;
739 }
740
741 */
742
743 static const char *
744 visible_email_addr(struct userNode *user, struct handle_info *hi)
745 {
746 if (hi->email_addr) {
747 if (oper_has_access(user, nickserv, nickserv_conf.email_visible_level, 1)) {
748 return hi->email_addr;
749 } else {
750 return "Set.";
751 }
752 } else {
753 return "Not set.";
754 }
755 }
756
757 struct handle_info *
758 smart_get_handle_info(struct userNode *service, struct userNode *user, const char *name)
759 {
760 struct handle_info *hi;
761 struct userNode *target;
762
763 switch (*name) {
764 case '*':
765 if (!(hi = get_handle_info(++name))) {
766 send_message(user, service, "MSG_HANDLE_UNKNOWN", name);
767 return 0;
768 }
769 return hi;
770 default:
771 if (!(target = GetUserH(name))) {
772 send_message(user, service, "MSG_NICK_UNKNOWN", name);
773 return 0;
774 }
775 if (IsLocal(target)) {
776 if (IsService(target))
777 send_message(user, service, "NSMSG_USER_IS_SERVICE", target->nick);
778 else
779 send_message(user, service, "MSG_USER_AUTHENTICATE", target->nick);
780 return 0;
781 }
782 if (!(hi = target->handle_info)) {
783 send_message(user, service, "MSG_USER_AUTHENTICATE", target->nick);
784 return 0;
785 }
786 return hi;
787 }
788 }
789
790 int
791 oper_outranks(struct userNode *user, struct handle_info *hi) {
792 if (user->handle_info->opserv_level > hi->opserv_level)
793 return 1;
794 if (user->handle_info->opserv_level == hi->opserv_level) {
795 if ((user->handle_info->opserv_level == 1000)
796 || (user->handle_info == hi)
797 || ((user->handle_info->opserv_level == 0)
798 && !(HANDLE_FLAGGED(hi, SUPPORT_HELPER) || HANDLE_FLAGGED(hi, NETWORK_HELPER))
799 && HANDLE_FLAGGED(user->handle_info, HELPING))) {
800 return 1;
801 }
802 }
803 send_message(user, nickserv, "MSG_USER_OUTRANKED", hi->handle);
804 return 0;
805 }
806
807 struct handle_info *
808 get_victim_oper(struct userNode *user, const char *target)
809 {
810 struct handle_info *hi;
811 if (!(hi = smart_get_handle_info(nickserv, user, target)))
812 return 0;
813 if (HANDLE_FLAGGED(user->handle_info, OPER_SUSPENDED)) {
814 send_message(user, nickserv, "MSG_OPER_SUSPENDED");
815 return 0;
816 }
817 return oper_outranks(user, hi) ? hi : NULL;
818 }
819
820 static int
821 valid_user_for(struct userNode *user, struct handle_info *hi)
822 {
823 unsigned int ii;
824
825 /* If no hostmasks on the account, allow it. */
826 if (!hi->masks->used)
827 return 1;
828 /* If any hostmask matches, allow it. */
829 for (ii=0; ii<hi->masks->used; ii++)
830 if (user_matches_glob(user, hi->masks->list[ii], 0, 0))
831 return 1;
832 /* If they are allowauthed to this account, allow it (removing the aa). */
833 if (dict_find(nickserv_allow_auth_dict, user->nick, NULL) == hi) {
834 dict_remove(nickserv_allow_auth_dict, user->nick);
835 return 2;
836 }
837 /* The user is not allowed to use this account. */
838 return 0;
839 }
840
841 static int
842 valid_user_sslfp(struct userNode *user, struct handle_info *hi)
843 {
844 unsigned int ii;
845
846 if (!hi->sslfps->used)
847 return 0;
848 if (!(user->sslfp))
849 return 0;
850
851 /* If any SSL fingerprint matches, allow it. */
852 for (ii=0; ii<hi->sslfps->used; ii++)
853 if (!irccasecmp(user->sslfp, hi->sslfps->list[ii]))
854 return 1;
855
856 /* No valid SSL fingerprint found. */
857 return 0;
858 }
859
860 static int
861 is_secure_password(const char *handle, const char *pass, struct userNode *user)
862 {
863 unsigned int i, len;
864 unsigned int cnt_digits = 0, cnt_upper = 0, cnt_lower = 0;
865 int p;
866
867 len = strlen(pass);
868 if (len < nickserv_conf.password_min_length) {
869 if (user)
870 send_message(user, nickserv, "NSMSG_PASSWORD_SHORT", nickserv_conf.password_min_length);
871 return 0;
872 }
873 if (!irccasecmp(pass, handle)) {
874 if (user)
875 send_message(user, nickserv, "NSMSG_PASSWORD_ACCOUNT");
876 return 0;
877 }
878 dict_find(nickserv_conf.weak_password_dict, pass, &p);
879 if (p) {
880 if (user)
881 send_message(user, nickserv, "NSMSG_PASSWORD_DICTIONARY");
882 return 0;
883 }
884 for (i=0; i<len; i++) {
885 if (isdigit(pass[i]))
886 cnt_digits++;
887 if (isupper(pass[i]))
888 cnt_upper++;
889 if (islower(pass[i]))
890 cnt_lower++;
891 }
892 if ((cnt_lower < nickserv_conf.password_min_lower)
893 || (cnt_upper < nickserv_conf.password_min_upper)
894 || (cnt_digits < nickserv_conf.password_min_digits)) {
895 if (user)
896 send_message(user, nickserv, "NSMSG_PASSWORD_READABLE", nickserv_conf.password_min_digits, nickserv_conf.password_min_upper, nickserv_conf.password_min_lower);
897 return 0;
898 }
899 return 1;
900 }
901
902 static auth_func_t *auth_func_list;
903 static void **auth_func_list_extra;
904 static unsigned int auth_func_size = 0, auth_func_used = 0;
905
906 void
907 reg_auth_func(auth_func_t func, void *extra)
908 {
909 if (auth_func_used == auth_func_size) {
910 if (auth_func_size) {
911 auth_func_size <<= 1;
912 auth_func_list = realloc(auth_func_list, auth_func_size*sizeof(auth_func_t));
913 auth_func_list_extra = realloc(auth_func_list_extra, auth_func_size*sizeof(void*));
914 } else {
915 auth_func_size = 8;
916 auth_func_list = malloc(auth_func_size*sizeof(auth_func_t));
917 auth_func_list_extra = malloc(auth_func_size*sizeof(void*));
918 }
919 }
920 auth_func_list[auth_func_used] = func;
921 auth_func_list_extra[auth_func_used++] = extra;
922 }
923
924 static handle_rename_func_t *rf_list;
925 static void **rf_list_extra;
926 static unsigned int rf_list_size, rf_list_used;
927
928 void
929 reg_handle_rename_func(handle_rename_func_t func, void *extra)
930 {
931 if (rf_list_used == rf_list_size) {
932 if (rf_list_size) {
933 rf_list_size <<= 1;
934 rf_list = realloc(rf_list, rf_list_size*sizeof(rf_list[0]));
935 rf_list_extra = realloc(rf_list_extra, rf_list_size*sizeof(void*));
936 } else {
937 rf_list_size = 8;
938 rf_list = malloc(rf_list_size*sizeof(rf_list[0]));
939 rf_list_extra = malloc(rf_list_size*sizeof(void*));
940 }
941 }
942 rf_list[rf_list_used] = func;
943 rf_list_extra[rf_list_used++] = extra;
944 }
945
946 static char *
947 generate_fakehost(struct handle_info *handle)
948 {
949 struct userNode *target;
950 extern const char *hidden_host_suffix;
951 static char buffer[HOSTLEN+1];
952 char *data;
953 int style = 1;
954
955 if (!handle->fakehost) {
956 data = conf_get_data("server/hidden_host_type", RECDB_QSTRING);
957 if (data)
958 style = atoi(data);
959
960 if (style == 1)
961 snprintf(buffer, sizeof(buffer), "%s.%s", handle->handle, hidden_host_suffix);
962 else if (style == 2) {
963 /* Due to the way fakehost is coded theres no way i can
964 get the exact user, so for now ill just take the first
965 authed user. */
966 for (target = handle->users; target; target = target->next_authed)
967 break;
968
969 snprintf(buffer, sizeof(buffer), "%s", target->crypthost);
970 }
971 return buffer;
972 } else if (handle->fakehost[0] == '.') {
973 /* A leading dot indicates the stored value is actually a title. */
974 snprintf(buffer, sizeof(buffer), "%s.%s.%s", handle->handle, handle->fakehost+1, nickserv_conf.titlehost_suffix);
975 return buffer;
976 }
977 return handle->fakehost;
978 }
979
980 static void
981 apply_fakehost(struct handle_info *handle)
982 {
983 struct userNode *target;
984 char *fake;
985
986 if (!handle->users)
987 return;
988 fake = generate_fakehost(handle);
989 for (target = handle->users; target; target = target->next_authed)
990 assign_fakehost(target, fake, 1);
991 }
992
993 void send_func_list(struct userNode *user)
994 {
995 unsigned int n;
996 struct handle_info *old_info;
997
998 old_info = user->handle_info;
999
1000 for (n=0; n<auth_func_used; n++)
1001 auth_func_list[n](user, old_info, auth_func_list_extra[n]);
1002 }
1003
1004 static void
1005 set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
1006 {
1007 unsigned int n;
1008 struct handle_info *old_info;
1009
1010 /* This can happen if somebody uses COOKIE while authed, or if
1011 * they re-auth to their current handle (which is silly, but users
1012 * are like that). */
1013 if (user->handle_info == hi)
1014 return;
1015
1016 if (user->handle_info) {
1017 struct userNode *other;
1018
1019 if (IsHelper(user))
1020 userList_remove(&curr_helpers, user);
1021
1022 /* remove from next_authed linked list */
1023 if (user->handle_info->users == user) {
1024 user->handle_info->users = user->next_authed;
1025 } else if (user->handle_info->users != NULL) {
1026 for (other = user->handle_info->users;
1027 other->next_authed != user;
1028 other = other->next_authed) ;
1029 other->next_authed = user->next_authed;
1030 } else {
1031 /* No users authed to the account - can happen if they get
1032 * killed for authing. */
1033 }
1034 /* if nobody left on old handle, and they're not an oper, remove !god */
1035 if (!user->handle_info->users && !user->handle_info->opserv_level)
1036 HANDLE_CLEAR_FLAG(user->handle_info, HELPING);
1037 /* record them as being last seen at this time */
1038 user->handle_info->lastseen = now;
1039 /* and record their hostmask */
1040 snprintf(user->handle_info->last_quit_host, sizeof(user->handle_info->last_quit_host), "%s@%s", user->ident, user->hostname);
1041 }
1042 old_info = user->handle_info;
1043 user->handle_info = hi;
1044 if (hi && !hi->users && !hi->opserv_level)
1045 HANDLE_CLEAR_FLAG(hi, HELPING);
1046
1047 /* Call auth handlers */
1048 if (!GetUserH(user->nick))
1049 user->loc = 1;
1050
1051 if (hi) {
1052 struct nick_info *ni;
1053
1054 HANDLE_CLEAR_FLAG(hi, FROZEN);
1055 if (nickserv_conf.warn_clone_auth) {
1056 struct userNode *other;
1057 for (other = hi->users; other; other = other->next_authed)
1058 send_message(other, nickserv, "NSMSG_CLONE_AUTH", user->nick, user->ident, user->hostname);
1059 }
1060
1061 /* Add this auth to users list of current auths */
1062 user->next_authed = hi->users;
1063 hi->users = user;
1064 hi->lastseen = now;
1065 /* Add to helpers list */
1066 if (IsHelper(user) && !userList_contains(&curr_helpers, user))
1067 userList_append(&curr_helpers, user);
1068
1069 /* Set the fakehost */
1070 if (hi->fakehost || old_info)
1071 apply_fakehost(hi);
1072
1073 if (stamp) {
1074 #ifdef WITH_PROTOCOL_P10
1075 /* Stamp users with their account name. */
1076 char *id = hi->handle;
1077 #else
1078 const char *id = "???";
1079 #endif
1080 /* Mark all the nicks registered to this
1081 * account as registered nicks
1082 * - Why not just this one? -rubin */
1083 if (!nickserv_conf.disable_nicks) {
1084 struct nick_info *ni2;
1085 for (ni2 = hi->nicks; ni2; ni2 = ni2->next) {
1086 if (!irccasecmp(user->nick, ni2->nick)) {
1087 user->modes |= FLAGS_REGNICK;
1088 break;
1089 }
1090 }
1091 }
1092 /* send the account to the ircd */
1093 StampUser(user, id, hi->registered);
1094 }
1095
1096 /* Stop trying to kick this user off their nick */
1097 if ((ni = get_nick_info(user->nick)) && (ni->owner == hi))
1098 timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
1099 } else {
1100 /* We cannot clear the user's account ID, unfortunately. */
1101 user->next_authed = NULL;
1102 }
1103
1104 /* Call auth handlers */
1105 if (GetUserH(user->nick)) {
1106 for (n=0; n<auth_func_used; n++) {
1107 auth_func_list[n](user, old_info, auth_func_list_extra[n]);
1108 if (user->dead)
1109 return;
1110 }
1111 }
1112 }
1113
1114 static struct handle_info*
1115 nickserv_register(struct userNode *user, struct userNode *settee, const char *handle, const char *passwd, int no_auth)
1116 {
1117 struct handle_info *hi;
1118 struct nick_info *ni;
1119 char crypted[MD5_CRYPT_LENGTH];
1120
1121 if ((hi = dict_find(nickserv_handle_dict, handle, NULL))) {
1122 if(user)
1123 send_message(user, nickserv, "NSMSG_HANDLE_EXISTS", handle);
1124 return 0;
1125 }
1126
1127 if(strlen(handle) > 30)
1128 {
1129 if(user)
1130 send_message(user, nickserv, "NSMSG_HANDLE_TOLONG", handle, 30);
1131 return 0;
1132 }
1133
1134 if (!is_secure_password(handle, passwd, user))
1135 return 0;
1136
1137 cryptpass(passwd, crypted);
1138 #ifdef WITH_LDAP
1139 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1140 int rc;
1141 rc = ldap_do_add(handle, (no_auth ? NULL : crypted), NULL);
1142 if(LDAP_SUCCESS != rc && LDAP_ALREADY_EXISTS != rc ) {
1143 if(user)
1144 send_message(user, nickserv, "NSMSG_LDAP_FAIL", ldap_err2string(rc));
1145 return 0;
1146 }
1147 }
1148 #endif
1149 hi = register_handle(handle, crypted, 0);
1150 hi->masks = alloc_string_list(1);
1151 hi->sslfps = alloc_string_list(1);
1152 hi->ignores = alloc_string_list(1);
1153 hi->users = NULL;
1154 hi->language = lang_C;
1155 hi->registered = now;
1156 hi->lastseen = now;
1157 hi->flags = HI_DEFAULT_FLAGS;
1158 if (settee && !no_auth)
1159 set_user_handle_info(settee, hi, 1);
1160
1161 if (user != settee) {
1162 if(user)
1163 send_message(user, nickserv, "NSMSG_OREGISTER_H_SUCCESS");
1164 }
1165 else if (nickserv_conf.disable_nicks) {
1166 if(user) {
1167 send_message(user, nickserv, "NSMSG_REGISTER_H_SUCCESS");
1168 }
1169 }
1170 else if (user && (ni = dict_find(nickserv_nick_dict, user->nick, NULL))) {
1171 if(user) {
1172 send_message(user, nickserv, "NSMSG_PARTIAL_REGISTER");
1173 }
1174 }
1175 else {
1176 if(user) {
1177 if (is_registerable_nick(user->nick)) {
1178 register_nick(user->nick, hi);
1179 send_message(user, nickserv, "NSMSG_REGISTER_HN_SUCCESS");
1180 }
1181 }
1182 }
1183 if (settee && (user != settee)) {
1184 if(user) {
1185 send_message(settee, nickserv, "NSMSG_OREGISTER_VICTIM", user->nick, hi->handle);
1186 }
1187 }
1188 return hi;
1189 }
1190
1191 static void
1192 nickserv_bake_cookie(struct handle_cookie *cookie)
1193 {
1194 cookie->hi->cookie = cookie;
1195 timeq_add(cookie->expires, nickserv_free_cookie, cookie);
1196 }
1197
1198 /* Contributed by the great sneep of afternet ;) */
1199 /* Since this gets used in a URL, we want to avoid stuff that confuses
1200 * email clients such as ] and ?. a-z, 0-9 only.
1201 */
1202 void genpass(char *str, int len)
1203 {
1204 int i = 0;
1205 char c = 0;
1206
1207 for(i = 0; i < len; i++)
1208 {
1209 do
1210 {
1211 c = (char)((float)rand() / (float)RAND_MAX * (float)256);
1212 } while(!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')));
1213 str[i] = c;
1214 }
1215 str[i] = '\0';
1216 return;
1217 }
1218
1219 static void
1220 nickserv_make_cookie(struct userNode *user, struct handle_info *hi, enum cookie_type type, const char *cookie_data, int weblink)
1221 {
1222 struct handle_cookie *cookie;
1223 char subject[128], body[4096], *misc;
1224 const char *netname, *fmt;
1225 int first_time = 0;
1226
1227 if (hi->cookie) {
1228 send_message(user, nickserv, "NSMSG_COOKIE_LIVE", hi->handle);
1229 return;
1230 }
1231
1232 cookie = calloc(1, sizeof(*cookie));
1233 cookie->hi = hi;
1234 cookie->type = type;
1235 cookie->data = cookie_data ? strdup(cookie_data) : NULL;
1236
1237 cookie->expires = now + nickserv_conf.cookie_timeout;
1238 /* Adding dedicated password gen function for more control -Rubin */
1239 genpass(cookie->cookie, 10);
1240 /*
1241 *inttobase64(cookie->cookie, rand(), 5);
1242 *inttobase64(cookie->cookie+5, rand(), 5);
1243 */
1244
1245 netname = nickserv_conf.network_name;
1246 subject[0] = 0;
1247
1248 switch (cookie->type) {
1249 case ACTIVATION:
1250 hi->passwd[0] = 0; /* invalidate password */
1251 send_message(user, nickserv, "NSMSG_USE_COOKIE_REGISTER");
1252 fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_SUBJECT");
1253 snprintf(subject, sizeof(subject), fmt, netname);
1254
1255 if(weblink)
1256 fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_BODY_WEB");
1257 else
1258 fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_BODY");
1259
1260 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1261 first_time = 1;
1262 break;
1263 case PASSWORD_CHANGE:
1264 send_message(user, nickserv, "NSMSG_USE_COOKIE_RESETPASS");
1265 fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1266 snprintf(subject, sizeof(subject), fmt, netname);
1267 if(weblink)
1268 fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1269 else
1270 fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_BODY");
1271 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1272 first_time = 0;
1273 break;
1274 case EMAIL_CHANGE:
1275 misc = hi->email_addr;
1276 hi->email_addr = cookie->data;
1277 #ifdef stupid_verify_old_email
1278 if (misc) {
1279 send_message(user, nickserv, "NSMSG_USE_COOKIE_EMAIL_2");
1280 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1281 snprintf(subject, sizeof(subject), fmt, netname);
1282 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1283 snprintf(body, sizeof(body), fmt, netname, cookie->cookie+COOKIELEN/2, nickserv->nick, self->name, hi->handle, COOKIELEN/2);
1284 mail_send(nickserv, hi, subject, body, 1);
1285 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1286 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle, COOKIELEN/2, hi->email_addr);
1287 first_time = 1;
1288 } else {
1289 #endif
1290 send_message(user, nickserv, "NSMSG_USE_COOKIE_EMAIL_1");
1291 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1292 snprintf(subject, sizeof(subject), fmt, netname);
1293 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_BODY");
1294 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1295 mail_send(nickserv, hi, subject, body, 1);
1296 subject[0] = 0;
1297 #ifdef stupid_verify_old_email
1298 }
1299 #endif
1300 hi->email_addr = misc;
1301 break;
1302 case ALLOWAUTH:
1303 fmt = handle_find_message(hi, "NSEMAIL_ALLOWAUTH_SUBJECT");
1304 snprintf(subject, sizeof(subject), fmt, netname);
1305 fmt = handle_find_message(hi, "NSEMAIL_ALLOWAUTH_BODY");
1306 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1307 send_message(user, nickserv, "NSMSG_USE_COOKIE_AUTH");
1308 break;
1309 default:
1310 log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d in nickserv_make_cookie.", cookie->type);
1311 break;
1312 }
1313 if (subject[0])
1314 mail_send(nickserv, hi, subject, body, first_time);
1315 nickserv_bake_cookie(cookie);
1316 }
1317
1318 static void
1319 nickserv_eat_cookie(struct handle_cookie *cookie)
1320 {
1321 cookie->hi->cookie = NULL;
1322 timeq_del(cookie->expires, nickserv_free_cookie, cookie, 0);
1323 nickserv_free_cookie(cookie);
1324 }
1325
1326 static void
1327 nickserv_free_email_addr(void *data)
1328 {
1329 handle_info_list_clean(data);
1330 free(data);
1331 }
1332
1333 static void
1334 nickserv_set_email_addr(struct handle_info *hi, const char *new_email_addr)
1335 {
1336 struct handle_info_list *hil;
1337 /* Remove from old handle_info_list ... */
1338 if (hi->email_addr && (hil = dict_find(nickserv_email_dict, hi->email_addr, 0))) {
1339 handle_info_list_remove(hil, hi);
1340 if (!hil->used) dict_remove(nickserv_email_dict, hil->tag);
1341 hi->email_addr = NULL;
1342 }
1343 /* Add to the new list.. */
1344 if (new_email_addr) {
1345 if (!(hil = dict_find(nickserv_email_dict, new_email_addr, 0))) {
1346 hil = calloc(1, sizeof(*hil));
1347 hil->tag = strdup(new_email_addr);
1348 handle_info_list_init(hil);
1349 dict_insert(nickserv_email_dict, hil->tag, hil);
1350 }
1351 handle_info_list_append(hil, hi);
1352 hi->email_addr = hil->tag;
1353 }
1354 }
1355
1356 static NICKSERV_FUNC(cmd_register)
1357 {
1358 irc_in_addr_t ip;
1359 struct handle_info *hi;
1360 const char *email_addr, *password;
1361 char syncpass[MD5_CRYPT_LENGTH];
1362 int no_auth, weblink;
1363
1364 if (checkDefCon(DEFCON_NO_NEW_NICKS) && !IsOper(user)) {
1365 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf.disable_nicks ? "accounts" : "nicknames");
1366 return 0;
1367 }
1368
1369 if (!IsOper(user) && !dict_size(nickserv_handle_dict)) {
1370 /* Require the first handle registered to belong to someone +o. */
1371 reply("NSMSG_REQUIRE_OPER");
1372 return 0;
1373 }
1374
1375 if (user->handle_info) {
1376 reply("NSMSG_USE_RENAME", user->handle_info->handle);
1377 return 0;
1378 }
1379
1380 if (IsRegistering(user)) {
1381 reply("NSMSG_ALREADY_REGISTERING");
1382 return 0;
1383 }
1384
1385 if (IsStamped(user)) {
1386 /* Unauthenticated users might still have been stamped
1387 previously and could therefore have a hidden host;
1388 do not allow them to register a new account. */
1389 reply("NSMSG_STAMPED_REGISTER");
1390 return 0;
1391 }
1392
1393 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf.email_required);
1394
1395 if(nickserv_conf.force_handles_lowercase)
1396 irc_strtolower(argv[1]);
1397 if (!is_valid_handle(argv[1])) {
1398 reply("NSMSG_BAD_HANDLE", argv[1]);
1399 return 0;
1400 }
1401
1402
1403 if ((argc >= 4) && nickserv_conf.email_enabled) {
1404 struct handle_info_list *hil;
1405 const char *str;
1406
1407 /* Remember email address. */
1408 email_addr = argv[3];
1409
1410 /* Check that the email address looks valid.. */
1411 if (!valid_email(email_addr)) {
1412 reply("NSMSG_BAD_EMAIL_ADDR");
1413 return 0;
1414 }
1415
1416 /* .. and that we are allowed to send to it. */
1417 if ((str = mail_prohibited_address(email_addr))) {
1418 reply("NSMSG_EMAIL_PROHIBITED", email_addr, str);
1419 return 0;
1420 }
1421
1422 /* If we do email verify, make sure we don't spam the address. */
1423 if ((hil = dict_find(nickserv_email_dict, email_addr, NULL))) {
1424 unsigned int nn;
1425 for (nn=0; nn<hil->used; nn++) {
1426 if (hil->list[nn]->cookie) {
1427 reply("NSMSG_EMAIL_UNACTIVATED");
1428 return 0;
1429 }
1430 }
1431 if (hil->used >= nickserv_conf.handles_per_email) {
1432 reply("NSMSG_EMAIL_OVERUSED");
1433 return 0;
1434 }
1435 }
1436
1437 no_auth = 1;
1438 } else {
1439 email_addr = 0;
1440 no_auth = 0;
1441 }
1442
1443 password = argv[2];
1444 argv[2] = "****";
1445 /* Webregister hack - send URL instead of IRC cookie
1446 * commands in email
1447 */
1448 if((argc >= 5) && !strcmp(argv[4],"WEBLINK"))
1449 weblink = 1;
1450 else
1451 weblink = 0;
1452 if (!(hi = nickserv_register(user, user, argv[1], password, no_auth)))
1453 return 0;
1454 /* Add any masks they should get. */
1455 if (nickserv_conf.default_hostmask) {
1456 string_list_append(hi->masks, strdup("*@*"));
1457 } else {
1458 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
1459 if (irc_in_addr_is_valid(user->ip) && !irc_pton(&ip, NULL, user->hostname))
1460 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
1461 }
1462
1463 /* If they're the first to register, give them level 1000. */
1464 if (dict_size(nickserv_handle_dict) == 1) {
1465 hi->opserv_level = 1000;
1466 reply("NSMSG_ROOT_HANDLE", argv[1]);
1467 }
1468
1469 /* Set their email address. */
1470 if (email_addr) {
1471 #ifdef WITH_LDAP
1472 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1473 int rc;
1474 if((rc = ldap_do_modify(hi->handle, NULL, email_addr)) != LDAP_SUCCESS) {
1475 /* Falied to update email in ldap, but still
1476 * updated it here.. what should we do? */
1477 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc));
1478 } else {
1479 nickserv_set_email_addr(hi, email_addr);
1480 }
1481 }
1482 else {
1483 nickserv_set_email_addr(hi, email_addr);
1484 }
1485 #else
1486 nickserv_set_email_addr(hi, email_addr);
1487 #endif
1488 }
1489
1490 /* If they need to do email verification, tell them. */
1491 if (no_auth)
1492 nickserv_make_cookie(user, hi, ACTIVATION, hi->passwd, weblink);
1493
1494 /* Set registering flag.. */
1495 user->modes |= FLAGS_REGISTERING;
1496
1497 if (nickserv_conf.sync_log) {
1498 cryptpass(password, syncpass);
1499 /*
1500 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1501 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1502 * -SiRVulcaN
1503 */
1504 SyncLog("REGISTER %s %s %s %s", hi->handle, syncpass, email_addr ? email_addr : "0", user->info);
1505 }
1506
1507 /* this wont work if email is required .. */
1508 process_adduser_pending(user);
1509
1510 return 1;
1511 }
1512
1513 static NICKSERV_FUNC(cmd_oregister)
1514 {
1515 struct userNode *settee = NULL;
1516 struct handle_info *hi;
1517 char* account = NULL;
1518 char* pass = NULL;
1519 char* email = NULL;
1520 char* mask = NULL;
1521 char* nick = NULL;
1522
1523 NICKSERV_MIN_PARMS(2);
1524
1525 account = argv[1];
1526 pass = argv[2];
1527 if(nickserv_conf.force_handles_lowercase)
1528 irc_strtolower(account);
1529 if (!is_valid_handle(argv[1])) {
1530 reply("NSMSG_BAD_HANDLE", argv[1]);
1531 return 0;
1532 }
1533 if (nickserv_conf.email_required) {
1534 NICKSERV_MIN_PARMS(3);
1535 email = argv[3];
1536 if (argc > 4) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1537 if (strchr(argv[4], '@'))
1538 mask = argv[4];
1539 else
1540 nick = argv[4];
1541 }
1542 if (argc >= 6) {
1543 nick = argv[5];
1544 }
1545 }
1546 else {
1547 if (argc > 3) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1548 if (strchr(argv[3], '@'))
1549 mask = argv[3];
1550 else
1551 nick = argv[3];
1552 }
1553 if (argc >= 5) {
1554 nick = argv[4];
1555 }
1556 }
1557 /* If they passed a nick, look for that user.. */
1558 if (nick && !(settee = GetUserH(nick))) {
1559 reply("MSG_NICK_UNKNOWN", argv[4]);
1560 return 0;
1561 }
1562 /* If the setee is already authed, we cant add a 2nd account for them.. */
1563 if (settee && settee->handle_info) {
1564 reply("NSMSG_USER_PREV_AUTH", settee->nick);
1565 return 0;
1566 }
1567 /* If there is no default mask in the conf, and they didn't pass a mask,
1568 * but we did find a user by nick, generate the mask */
1569 if (!mask) {
1570 if (nickserv_conf.default_hostmask)
1571 mask = "*@*";
1572 else if (settee)
1573 mask = generate_hostmask(settee, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
1574 else {
1575 reply("NSMSG_REGISTER_BAD_NICKMASK");
1576 return 0;
1577 }
1578 }
1579
1580 if (!(hi = nickserv_register(user, settee, account, pass, 0))) {
1581 return 0; /* error reply handled by above */
1582 }
1583 if (email) {
1584 #ifdef WITH_LDAP
1585 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1586 int rc;
1587 if((rc = ldap_do_modify(hi->handle, NULL, email)) != LDAP_SUCCESS) {
1588 /* Falied to update email in ldap, but still
1589 * updated it here.. what should we do? */
1590 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc));
1591 } else {
1592 nickserv_set_email_addr(hi, email);
1593 }
1594 }
1595 else {
1596 nickserv_set_email_addr(hi, email);
1597 }
1598 #else
1599 nickserv_set_email_addr(hi, email);
1600 #endif
1601 }
1602 if (mask) {
1603 char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
1604 if (mask_canonicalized)
1605 string_list_append(hi->masks, mask_canonicalized);
1606 }
1607
1608 if (nickserv_conf.sync_log)
1609 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, email ? email : "@", user->info); /* Send just @ for email if none */
1610 return 1;
1611 }
1612
1613 static int
1614 nickserv_ignore(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, char *mask)
1615 {
1616 unsigned int i;
1617 struct userNode *target;
1618 char *new_mask = strdup(pretty_mask(mask));
1619 for (i=0; i<hi->ignores->used; i++) {
1620 if (!irccasecmp(new_mask, hi->ignores->list[i])) {
1621 reply("NSMSG_ADDIGNORE_ALREADY", new_mask);
1622 free(new_mask);
1623 return 0;
1624 }
1625 }
1626 string_list_append(hi->ignores, new_mask);
1627 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask);
1628
1629 for (target = hi->users; target; target = target->next_authed) {
1630 irc_silence(target, new_mask, 1);
1631 }
1632 return 1;
1633 }
1634
1635 static NICKSERV_FUNC(cmd_addignore)
1636 {
1637 NICKSERV_MIN_PARMS(2);
1638
1639 return nickserv_ignore(cmd, user, user->handle_info, argv[1]);
1640 }
1641
1642 static NICKSERV_FUNC(cmd_oaddignore)
1643 {
1644 struct handle_info *hi;
1645
1646 NICKSERV_MIN_PARMS(3);
1647 if (!(hi = get_victim_oper(user, argv[1])))
1648 return 0;
1649
1650 return nickserv_ignore(cmd, user, hi, argv[2]);
1651 }
1652
1653 static int
1654 nickserv_delignore(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, char *del_mask)
1655 {
1656 unsigned int i;
1657 struct userNode *target;
1658 char *pmask = strdup(pretty_mask(del_mask));
1659 for (i=0; i<hi->ignores->used; i++) {
1660 if (!strcmp(pmask, hi->ignores->list[i]) || !strcmp(del_mask, hi->ignores->list[i])) {
1661 char *old_mask = hi->ignores->list[i];
1662 hi->ignores->list[i] = hi->ignores->list[--hi->ignores->used];
1663 reply("NSMSG_DELMASK_SUCCESS", old_mask);
1664 for (target = hi->users; target; target = target->next_authed) {
1665 irc_silence(target, old_mask, 0);
1666 }
1667 free(old_mask);
1668 free(pmask);
1669 return 1;
1670 }
1671 }
1672 reply("NSMSG_DELMASK_NOT_FOUND");
1673 return 0;
1674 }
1675
1676 static NICKSERV_FUNC(cmd_delignore)
1677 {
1678 NICKSERV_MIN_PARMS(2);
1679 return nickserv_delignore(cmd, user, user->handle_info, argv[1]);
1680 }
1681
1682 static NICKSERV_FUNC(cmd_odelignore)
1683 {
1684 struct handle_info *hi;
1685 NICKSERV_MIN_PARMS(3);
1686 if (!(hi = get_victim_oper(user, argv[1])))
1687 return 0;
1688 return nickserv_delignore(cmd, user, hi, argv[2]);
1689 }
1690
1691 static NICKSERV_FUNC(cmd_handleinfo)
1692 {
1693 char buff[400];
1694 unsigned int i, pos=0, herelen;
1695 struct userNode *target, *next_un;
1696 struct handle_info *hi;
1697 const char *nsmsg_none;
1698
1699 if (argc < 2) {
1700 if (!(hi = user->handle_info)) {
1701 reply("NSMSG_MUST_AUTH");
1702 return 0;
1703 }
1704 } else if (!(hi = modcmd_get_handle_info(user, argv[1]))) {
1705 return 0;
1706 }
1707
1708 nsmsg_none = handle_find_message(hi, "MSG_NONE");
1709 reply("NSMSG_HANDLEINFO_ON", hi->handle);
1710 reply("MSG_BAR");
1711 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi->registered));
1712
1713 if (!hi->users) {
1714 intervalString(buff, now - hi->lastseen, user->handle_info);
1715 reply("NSMSG_HANDLEINFO_LASTSEEN", buff);
1716 } else {
1717 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1718 }
1719
1720 reply("NSMSG_HANDLEINFO_INFOLINE", (hi->infoline ? hi->infoline : nsmsg_none));
1721 if (HANDLE_FLAGGED(hi, FROZEN))
1722 reply("NSMSG_HANDLEINFO_VACATION");
1723
1724 if (oper_has_access(user, cmd->parent->bot, 0, 1)) {
1725 struct do_not_register *dnr;
1726 if ((dnr = chanserv_is_dnr(NULL, hi)))
1727 reply("NSMSG_HANDLEINFO_DNR", dnr->setter, dnr->reason);
1728 if ((user->handle_info->opserv_level < 900) && !oper_outranks(user, hi))
1729 return 1;
1730 } else if (hi != user->handle_info) {
1731 reply("NSMSG_HANDLEINFO_END");
1732 return 1;
1733 }
1734
1735 if (IsOper(user))
1736 reply("NSMSG_HANDLEINFO_KARMA", hi->karma);
1737
1738 if (nickserv_conf.email_enabled)
1739 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user, hi));
1740
1741 if (hi->cookie) {
1742 const char *type;
1743 switch (hi->cookie->type) {
1744 case ACTIVATION: type = "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1745 case PASSWORD_CHANGE: type = "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1746 case EMAIL_CHANGE: type = "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1747 case ALLOWAUTH: type = "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1748 default: type = "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1749 }
1750 reply(type);
1751 }
1752
1753 if (hi->flags) {
1754 unsigned long flen = 1;
1755 char flags[34]; /* 32 bits possible plus '+' and '\0' */
1756 flags[0] = '+';
1757 for (i=0, flen=1; handle_flags[i]; i++)
1758 if (hi->flags & 1 << i)
1759 flags[flen++] = handle_flags[i];
1760 flags[flen] = 0;
1761 reply("NSMSG_HANDLEINFO_FLAGS", flags);
1762 } else {
1763 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none);
1764 }
1765
1766 if (HANDLE_FLAGGED(hi, SUPPORT_HELPER)
1767 || HANDLE_FLAGGED(hi, NETWORK_HELPER)
1768 || (hi->opserv_level > 0)) {
1769 reply("NSMSG_HANDLEINFO_EPITHET", (hi->epithet ? hi->epithet : nsmsg_none));
1770 }
1771
1772 if (IsHelping(user) || IsOper(user))
1773 {
1774 if (hi->note)
1775 {
1776 char date[64];
1777 strftime(date, 64, "%b %d %Y", localtime(&hi->note->date));
1778 reply("NSMSG_HANDLEINFO_NOTE", hi->note->setter, date, hi->note->note);
1779 }
1780 }
1781
1782 if (hi->fakehost)
1783 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi->fakehost ? hi->fakehost : handle_find_message(hi, "MSG_NONE")));
1784
1785 if (hi->last_quit_host[0])
1786 reply("NSMSG_HANDLEINFO_LAST_HOST", hi->last_quit_host);
1787 else
1788 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1789
1790 if (nickserv_conf.disable_nicks) {
1791 /* nicks disabled; don't show anything about registered nicks */
1792 } else if (hi->nicks) {
1793 struct nick_info *ni, *next_ni;
1794 for (ni = hi->nicks; ni; ni = next_ni) {
1795 herelen = strlen(ni->nick);
1796 if (pos + herelen + 1 > ArrayLength(buff)) {
1797 next_ni = ni;
1798 goto print_nicks_buff;
1799 } else {
1800 next_ni = ni->next;
1801 }
1802 memcpy(buff+pos, ni->nick, herelen);
1803 pos += herelen; buff[pos++] = ' ';
1804 if (!next_ni) {
1805 print_nicks_buff:
1806 buff[pos-1] = 0;
1807 reply("NSMSG_HANDLEINFO_NICKS", buff);
1808 pos = 0;
1809 }
1810 }
1811 } else {
1812 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none);
1813 }
1814
1815 if (hi->masks->used) {
1816 for (i=0; i < hi->masks->used; i++) {
1817 herelen = strlen(hi->masks->list[i]);
1818 if (pos + herelen + 1 > ArrayLength(buff)) {
1819 i--;
1820 goto print_mask_buff;
1821 }
1822 memcpy(buff+pos, hi->masks->list[i], herelen);
1823 pos += herelen; buff[pos++] = ' ';
1824 if (i+1 == hi->masks->used) {
1825 print_mask_buff:
1826 buff[pos-1] = 0;
1827 reply("NSMSG_HANDLEINFO_MASKS", buff);
1828 pos = 0;
1829 }
1830 }
1831 } else {
1832 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none);
1833 }
1834
1835 if (hi->sslfps->used) {
1836 for (i=0; i < hi->sslfps->used; i++) {
1837 herelen = strlen(hi->sslfps->list[i]);
1838 if (pos + herelen + 1 > ArrayLength(buff)) {
1839 i--;
1840 goto print_sslfp_buff;
1841 }
1842 memcpy(buff+pos, hi->sslfps->list[i], herelen);
1843 pos += herelen; buff[pos++] = ' ';
1844 if (i+1 == hi->sslfps->used) {
1845 print_sslfp_buff:
1846 buff[pos-1] = 0;
1847 reply("NSMSG_HANDLEINFO_SSLFPS", buff);
1848 pos = 0;
1849 }
1850 }
1851 } else {
1852 reply("NSMSG_HANDLEINFO_SSLFPS", nsmsg_none);
1853 }
1854
1855 if (hi->ignores->used) {
1856 for (i=0; i < hi->ignores->used; i++) {
1857 herelen = strlen(hi->ignores->list[i]);
1858 if (pos + herelen + 1 > ArrayLength(buff)) {
1859 i--;
1860 goto print_ignore_buff;
1861 }
1862 memcpy(buff+pos, hi->ignores->list[i], herelen);
1863 pos += herelen; buff[pos++] = ' ';
1864 if (i+1 == hi->ignores->used) {
1865 print_ignore_buff:
1866 buff[pos-1] = 0;
1867 reply("NSMSG_HANDLEINFO_IGNORES", buff);
1868 pos = 0;
1869 }
1870 }
1871 } else {
1872 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none);
1873 }
1874
1875 if (hi->channels) {
1876 struct userData *chan, *next;
1877 char *name;
1878
1879 for (chan = hi->channels; chan; chan = next) {
1880 next = chan->u_next;
1881 name = chan->channel->channel->name;
1882 herelen = strlen(name);
1883 if (pos + herelen + 7 > ArrayLength(buff)) {
1884 next = chan;
1885 goto print_chans_buff;
1886 }
1887 if (IsUserSuspended(chan))
1888 buff[pos++] = '-';
1889 pos += sprintf(buff+pos, "%s:%s ", user_level_name_from_level(chan->access), name);
1890 if (next == NULL) {
1891 print_chans_buff:
1892 buff[pos-1] = 0;
1893 reply("NSMSG_HANDLEINFO_CHANNELS", buff);
1894 pos = 0;
1895 }
1896 }
1897 } else {
1898 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none);
1899 }
1900
1901 for (target = hi->users; target; target = next_un) {
1902 herelen = strlen(target->nick);
1903 if (pos + herelen + 1 > ArrayLength(buff)) {
1904 next_un = target;
1905 goto print_cnick_buff;
1906 } else {
1907 next_un = target->next_authed;
1908 }
1909 memcpy(buff+pos, target->nick, herelen);
1910 pos += herelen; buff[pos++] = ' ';
1911 if (!next_un) {
1912 print_cnick_buff:
1913 buff[pos-1] = 0;
1914 reply("NSMSG_HANDLEINFO_CURRENT", buff);
1915 pos = 0;
1916 }
1917 }
1918
1919 reply("NSMSG_HANDLEINFO_END");
1920 return 1 | ((hi != user->handle_info) ? CMD_LOG_STAFF : 0);
1921 }
1922
1923 static NICKSERV_FUNC(cmd_userinfo)
1924 {
1925 struct userNode *target;
1926
1927 NICKSERV_MIN_PARMS(2);
1928 if (!(target = GetUserH(argv[1]))) {
1929 reply("MSG_NICK_UNKNOWN", argv[1]);
1930 return 0;
1931 }
1932 if (target->handle_info)
1933 reply("NSMSG_USERINFO_AUTHED_AS", target->nick, target->handle_info->handle);
1934 else
1935 reply("NSMSG_USERINFO_NOT_AUTHED", target->nick);
1936 return 1;
1937 }
1938
1939 static NICKSERV_FUNC(cmd_nickinfo)
1940 {
1941 struct nick_info *ni;
1942
1943 NICKSERV_MIN_PARMS(2);
1944 if (!(ni = get_nick_info(argv[1]))) {
1945 reply("MSG_NICK_UNKNOWN", argv[1]);
1946 return 0;
1947 }
1948 reply("NSMSG_NICKINFO_OWNER", ni->nick, ni->owner->handle);
1949 return 1;
1950 }
1951
1952 static NICKSERV_FUNC(cmd_rename_handle)
1953 {
1954 struct handle_info *hi;
1955 struct userNode *uNode;
1956 char *old_handle;
1957 unsigned int nn;
1958
1959 NICKSERV_MIN_PARMS(3);
1960 if(nickserv_conf.force_handles_lowercase)
1961 irc_strtolower(argv[2]);
1962 if (!(hi = get_victim_oper(user, argv[1])))
1963 return 0;
1964 if (!is_valid_handle(argv[2])) {
1965 reply("NSMSG_FAIL_RENAME", argv[1], argv[2]);
1966 return 0;
1967 }
1968 if (get_handle_info(argv[2])) {
1969 reply("NSMSG_HANDLE_EXISTS", argv[2]);
1970 return 0;
1971 }
1972 if(strlen(argv[2]) > 30)
1973 {
1974 reply("NMSG_HANDLE_TOLONG", argv[2], 30);
1975 return 0;
1976 }
1977 #ifdef WITH_LDAP
1978 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1979 int rc;
1980 if( (rc = ldap_rename_account(hi->handle, argv[2])) != LDAP_SUCCESS) {
1981 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
1982 return 0;
1983 }
1984 }
1985 #endif
1986
1987 dict_remove2(nickserv_handle_dict, old_handle = hi->handle, 1);
1988 hi->handle = strdup(argv[2]);
1989 dict_insert(nickserv_handle_dict, hi->handle, hi);
1990 for (nn=0; nn<rf_list_used; nn++)
1991 rf_list[nn](hi, old_handle, rf_list_extra[nn]);
1992
1993 if (nickserv_conf.sync_log) {
1994 for (uNode = hi->users; uNode; uNode = uNode->next_authed)
1995 irc_rename(uNode, hi->handle);
1996
1997 SyncLog("RENAME %s %s", old_handle, hi->handle);
1998 }
1999
2000 reply("NSMSG_HANDLE_CHANGED", old_handle, hi->handle);
2001 global_message_args(MESSAGE_RECIPIENT_OPERS, "NSMSG_ACCOUNT_RENAMED",
2002 user->handle_info->handle, old_handle, hi->handle);
2003
2004 free(old_handle);
2005 return 1;
2006 }
2007
2008 static failpw_func_t *failpw_func_list;
2009 static void **failpw_func_list_extra;
2010 static unsigned int failpw_func_size = 0, failpw_func_used = 0;
2011
2012 void
2013 reg_failpw_func(failpw_func_t func, void *extra)
2014 {
2015 if (failpw_func_used == failpw_func_size) {
2016 if (failpw_func_size) {
2017 failpw_func_size <<= 1;
2018 failpw_func_list = realloc(failpw_func_list, failpw_func_size*sizeof(failpw_func_t));
2019 failpw_func_list_extra = realloc(failpw_func_list_extra, failpw_func_size*sizeof(void*));
2020 } else {
2021 failpw_func_size = 8;
2022 failpw_func_list = malloc(failpw_func_size*sizeof(failpw_func_t));
2023 failpw_func_list_extra = malloc(failpw_func_size*sizeof(void*));
2024 }
2025 }
2026 failpw_func_list[failpw_func_used] = func;
2027 failpw_func_list_extra[failpw_func_used++] = extra;
2028 }
2029
2030 /*
2031 * Return hi if the handle/pass pair matches, NULL if it doesnt.
2032 *
2033 * called by nefariouses enhanced AC login-on-connect code
2034 *
2035 */
2036 struct handle_info *loc_auth(char *handle, char *password, char *userhost)
2037 {
2038 int pw_arg, used, maxlogins;
2039 unsigned int ii;
2040 int wildmask = 0;
2041 struct handle_info *hi;
2042 struct userNode *other;
2043 #ifdef WITH_LDAP
2044 int ldap_result = LDAP_SUCCESS;
2045 char *email = NULL;
2046 #endif
2047
2048 hi = dict_find(nickserv_handle_dict, handle, NULL);
2049 pw_arg = 2;
2050
2051 #ifdef WITH_LDAP
2052 if(nickserv_conf.ldap_enable) {
2053 ldap_result = ldap_check_auth(handle, password);
2054 if(ldap_result != LDAP_SUCCESS) {
2055 return NULL;
2056 }
2057 }
2058 #else
2059 if (!hi) {
2060 return NULL;
2061 }
2062
2063 if (!checkpass(password, hi->passwd)) {
2064 return NULL;
2065 }
2066 #endif
2067 #ifdef WITH_LDAP
2068 /* ldap libs are present but we are not using them... */
2069 if( !nickserv_conf.ldap_enable ) {
2070 if (!hi) {
2071 return NULL;
2072 }
2073 if (!checkpass(password, hi->passwd)) {
2074 return NULL;
2075 }
2076 }
2077 else if( (!hi) && ldap_result == LDAP_SUCCESS && nickserv_conf.ldap_autocreate) {
2078 /* user not found, but authed to ldap successfully..
2079 * create the account.
2080 */
2081 char *mask;
2082 int rc;
2083
2084 /* Add a *@* mask */
2085 /* TODO if userhost is not null, build mask based on that. */
2086 if(nickserv_conf.default_hostmask)
2087 mask = "*@*";
2088 else
2089 return NULL; /* They dont have a *@* mask so they can't loc */
2090
2091 if(!(hi = nickserv_register(NULL, NULL, handle, password, 0))) {
2092 return 0; /* couldn't add the user for some reason */
2093 }
2094
2095 if((rc = ldap_get_user_info(handle, &email) != LDAP_SUCCESS))
2096 {
2097 if(nickserv_conf.email_required) {
2098 return 0;
2099 }
2100 }
2101 if(email) {
2102 nickserv_set_email_addr(hi, email);
2103 free(email);
2104 }
2105 if(mask) {
2106 char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
2107 string_list_append(hi->masks, mask_canonicalized);
2108 }
2109 if(nickserv_conf.sync_log)
2110 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, "@", handle);
2111 }
2112 #endif
2113
2114 /* Still no account, so just fail out */
2115 if (!hi) {
2116 return NULL;
2117 }
2118
2119 /* We don't know the users hostname, or anything because they
2120 * havn't registered yet. So we can only allow LOC if your
2121 * account has *@* as a hostmask.
2122 *
2123 * UPDATE: New nefarious LOC supports u@h
2124 */
2125 if(userhost) {
2126 char *buf;
2127 char *ident;
2128 char *realhost;
2129 char *ip;
2130 char *uh;
2131 char *ui;
2132
2133 buf = strdup(userhost);
2134 ident = mysep(&buf, "@");
2135 realhost = mysep(&buf, ":");
2136 ip = mysep(&buf, ":");
2137 if(!ip || !realhost || !ident) {
2138 free(buf);
2139 return NULL; /* Invalid AC request, just quit */
2140 }
2141 uh = malloc(strlen(userhost));
2142 ui = malloc(strlen(userhost));
2143 sprintf(uh, "%s@%s", ident, realhost);
2144 sprintf(ui, "%s@%s", ident, ip);
2145 for (ii=0; ii<hi->masks->used; ii++)
2146 {
2147 if(match_ircglob(uh, hi->masks->list[ii])
2148 || match_ircglob(ui, hi->masks->list[ii]))
2149 {
2150 wildmask++;
2151 break;
2152 }
2153 }
2154 free(buf);
2155 free(uh);
2156 free(ui);
2157 }
2158 else {
2159
2160 for (ii=0; ii<hi->masks->used; ii++)
2161 {
2162 if (!strcmp(hi->masks->list[ii], "*@*"))
2163 {
2164 wildmask++;
2165 break;
2166 }
2167 }
2168 }
2169 if(wildmask < 1)
2170 return NULL;
2171
2172 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
2173 return NULL;
2174 }
2175
2176 maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
2177 for (used = 0, other = hi->users; other; other = other->next_authed) {
2178 if (++used >= maxlogins) {
2179 return NULL;
2180 }
2181 }
2182 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2183 return hi;
2184 }
2185
2186 static NICKSERV_FUNC(cmd_auth)
2187 {
2188 char *privv[MAXNUMPARAMS];
2189 int privc, i;
2190 int pw_arg, used, maxlogins;
2191 struct handle_info *hi;
2192 const char *passwd;
2193 const char *handle;
2194 struct userNode *other;
2195 #ifdef WITH_LDAP
2196 int ldap_result = LDAP_OTHER;
2197 char *email = NULL;
2198 #endif
2199
2200 if (user->handle_info) {
2201 reply("NSMSG_ALREADY_AUTHED", user->handle_info->handle);
2202 return 0;
2203 }
2204 if (IsStamped(user)) {
2205 /* Unauthenticated users might still have been stamped
2206 previously and could therefore have a hidden host;
2207 do not allow them to authenticate. */
2208 reply("NSMSG_STAMPED_AUTH");
2209 return 0;
2210 }
2211 if (argc == 3) {
2212 passwd = argv[2];
2213 handle = argv[1];
2214 pw_arg = 2;
2215 hi = dict_find(nickserv_handle_dict, argv[1], NULL);
2216 } else if (argc == 2) {
2217 passwd = argv[1];
2218 pw_arg = 1;
2219 if (nickserv_conf.disable_nicks) {
2220 hi = get_handle_info(user->nick);
2221 } else {
2222 /* try to look up their handle from their nick */
2223 /* TODO: handle ldap auth on nickserv style networks, too */
2224 struct nick_info *ni;
2225 ni = get_nick_info(user->nick);
2226 if (!ni) {
2227 reply("NSMSG_NICK_NOT_REGISTERED", user->nick);
2228 return 0;
2229 }
2230 hi = ni->owner;
2231 }
2232 if (hi) {
2233 handle = hi->handle;
2234 } else {
2235 handle = user->nick;
2236 }
2237 } else {
2238 reply("MSG_MISSING_PARAMS", argv[0]);
2239 svccmd_send_help_brief(user, nickserv, cmd);
2240 return 0;
2241 }
2242
2243 #ifdef WITH_LDAP
2244 if(strchr(argv[1], '<') || strchr(handle, '>')) {
2245 reply("NSMSG_NO_ANGLEBRACKETS");
2246 return 0;
2247 }
2248 if (!is_valid_handle(handle)) {
2249 reply("NSMSG_BAD_HANDLE", handle);
2250 return 0;
2251 }
2252
2253 if(nickserv_conf.ldap_enable) {
2254 ldap_result = ldap_check_auth(handle, passwd);
2255 /* Get the users email address and update it */
2256 if(ldap_result == LDAP_SUCCESS) {
2257 int rc;
2258 if((rc = ldap_get_user_info(handle, &email) != LDAP_SUCCESS))
2259 {
2260 if(nickserv_conf.email_required) {
2261 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc));
2262 return 0;
2263 }
2264 }
2265 }
2266 else if(ldap_result != LDAP_INVALID_CREDENTIALS) {
2267 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result));
2268 return 0;
2269 }
2270 }
2271 #endif
2272
2273 if (!hi) {
2274 #ifdef WITH_LDAP
2275 if(nickserv_conf.ldap_enable && ldap_result == LDAP_SUCCESS && nickserv_conf.ldap_autocreate) {
2276 /* user not found, but authed to ldap successfully..
2277 * create the account.
2278 */
2279 char *mask;
2280 if(!(hi = nickserv_register(user, NULL, argv[1], argv[2], 0))) {
2281 reply("NSMSG_UNABLE_TO_ADD");
2282 return 0; /* couldn't add the user for some reason */
2283 }
2284 /* Add a *@* mask */
2285 if(nickserv_conf.default_hostmask)
2286 mask = "*@*";
2287 else
2288 mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
2289
2290 if(mask) {
2291 char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
2292 string_list_append(hi->masks, mask_canonicalized);
2293 }
2294 if(email) {
2295 nickserv_set_email_addr(hi, email);
2296 free(email);
2297 }
2298 if(nickserv_conf.sync_log)
2299 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, email ? email : "@", user->info);
2300 }
2301 else {
2302 #endif
2303 reply("NSMSG_HANDLE_NOT_FOUND");
2304 return 0;
2305 #ifdef WITH_LDAP
2306 }
2307 #endif
2308 }
2309 /* Responses from here on look up the language used by the handle they asked about. */
2310 if (!valid_user_for(user, hi)) {
2311 if (hi->email_addr && nickserv_conf.email_enabled)
2312 send_message_type(4, user, cmd->parent->bot,
2313 handle_find_message(hi, "NSMSG_USE_AUTHCOOKIE"),
2314 hi->handle);
2315 else
2316 send_message_type(4, user, cmd->parent->bot,
2317 handle_find_message(hi, "NSMSG_HOSTMASK_INVALID"),
2318 hi->handle);
2319 argv[pw_arg] = "BADMASK";
2320 return 1;
2321 }
2322 #ifdef WITH_LDAP
2323 if(( ( nickserv_conf.ldap_enable && ldap_result == LDAP_INVALID_CREDENTIALS ) ||
2324 ( (!nickserv_conf.ldap_enable) && (!checkpass(passwd, hi->passwd)) ) ) && !valid_user_sslfp(user, hi)) {
2325 #else
2326 if (!checkpass(passwd, hi->passwd) && !valid_user_sslfp(user, hi)) {
2327 #endif
2328 unsigned int n;
2329 send_message_type(4, user, cmd->parent->bot,
2330 handle_find_message(hi, "NSMSG_PASSWORD_INVALID"));
2331 argv[pw_arg] = "BADPASS";
2332 for (n=0; n<failpw_func_used; n++)
2333 failpw_func_list[n](user, hi, failpw_func_list_extra[n]);
2334 if (nickserv_conf.autogag_enabled) {
2335 if (!user->auth_policer.params) {
2336 user->auth_policer.last_req = now;
2337 user->auth_policer.params = nickserv_conf.auth_policer_params;
2338 }
2339 if (!policer_conforms(&user->auth_policer, now, 1.0)) {
2340 char *hostmask;
2341 hostmask = generate_hostmask(user, GENMASK_STRICT_HOST|GENMASK_BYIP|GENMASK_NO_HIDING);
2342 log_module(NS_LOG, LOG_INFO, "%s auto-gagged for repeated password guessing.", hostmask);
2343 gag_create(hostmask, nickserv->nick, "Repeated password guessing.", now+nickserv_conf.autogag_duration);
2344 free(hostmask);
2345 argv[pw_arg] = "GAGGED";
2346 }
2347 }
2348 return 1;
2349 }
2350 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
2351 send_message_type(4, user, cmd->parent->bot,
2352 handle_find_message(hi, "NSMSG_HANDLE_SUSPENDED"));
2353 argv[pw_arg] = "SUSPENDED";
2354 return 1;
2355 }
2356 maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
2357 for (used = 0, other = hi->users; other; other = other->next_authed) {
2358 if (++used >= maxlogins) {
2359 send_message_type(4, user, cmd->parent->bot,
2360 handle_find_message(hi, "NSMSG_MAX_LOGINS"),
2361 maxlogins);
2362 argv[pw_arg] = "MAXLOGINS";
2363 return 1;
2364 }
2365 }
2366
2367 set_user_handle_info(user, hi, 1);
2368 if (nickserv_conf.email_required && !hi->email_addr)
2369 reply("NSMSG_PLEASE_SET_EMAIL");
2370 if (!is_secure_password(hi->handle, passwd, NULL))
2371 reply("NSMSG_WEAK_PASSWORD");
2372 if (hi->passwd[0] != '$')
2373 cryptpass(passwd, hi->passwd);
2374
2375 /* If a channel was waiting for this user to auth,
2376 * finish adding them */
2377 process_adduser_pending(user);
2378
2379 reply("NSMSG_AUTH_SUCCESS");
2380
2381
2382 /* Set +x if autohide is on */
2383 if(HANDLE_FLAGGED(hi, AUTOHIDE))
2384 irc_umode(user, "+x");
2385
2386 if(!IsOper(user)) /* If they arnt already opered.. */
2387 {
2388 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2389 if( nickserv_conf.auto_admin[0] && hi->opserv_level >= opserv_conf_admin_level())
2390 {
2391 if (nickserv_conf.auto_admin_privs[0]) {
2392 irc_raw_privs(user, nickserv_conf.auto_admin_privs);
2393 privc = split_line(strdup(nickserv_conf.auto_admin_privs), false, MAXNUMPARAMS, privv);
2394 for (i = 0; i < privc; i++) {
2395 client_modify_priv_by_name(user, privv[i], 1);
2396 }
2397 }
2398 irc_umode(user,nickserv_conf.auto_admin);
2399 reply("NSMSG_AUTO_OPER_ADMIN");
2400 }
2401 else if (nickserv_conf.auto_oper[0] && hi->opserv_level > 0)
2402 {
2403 if (nickserv_conf.auto_oper_privs[0]) {
2404 irc_raw_privs(user, nickserv_conf.auto_oper_privs);
2405 privc = split_line(strdup(nickserv_conf.auto_oper_privs), false, MAXNUMPARAMS, privv);
2406 for (i = 0; i < privc; i++) {
2407 client_modify_priv_by_name(user, privv[i], 1);
2408 }
2409 }
2410 irc_umode(user,nickserv_conf.auto_oper);
2411 reply("NSMSG_AUTO_OPER");
2412 }
2413 }
2414
2415 /* Wipe out the pass for the logs */
2416
2417 if (!hi->masks->used) {
2418 irc_in_addr_t ip;
2419 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
2420 if (irc_in_addr_is_valid(user->ip) && irc_pton(&ip, NULL, user->hostname))
2421 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
2422 }
2423
2424 argv[pw_arg] = "****";
2425 return 1;
2426 }
2427
2428 static allowauth_func_t *allowauth_func_list;
2429 static void **allowauth_func_list_extra;
2430 static unsigned int allowauth_func_size = 0, allowauth_func_used = 0;
2431
2432 void
2433 reg_allowauth_func(allowauth_func_t func, void *extra)
2434 {
2435 if (allowauth_func_used == allowauth_func_size) {
2436 if (allowauth_func_size) {
2437 allowauth_func_size <<= 1;
2438 allowauth_func_list = realloc(allowauth_func_list, allowauth_func_size*sizeof(allowauth_func_t));
2439 allowauth_func_list_extra = realloc(allowauth_func_list_extra, allowauth_func_size*sizeof(void*));
2440 } else {
2441 allowauth_func_size = 8;
2442 allowauth_func_list = malloc(allowauth_func_size*sizeof(allowauth_func_t));
2443 allowauth_func_list_extra = malloc(allowauth_func_size*sizeof(void*));
2444 }
2445 }
2446 allowauth_func_list[allowauth_func_used] = func;
2447 allowauth_func_list_extra[allowauth_func_used++] = extra;
2448 }
2449
2450 static NICKSERV_FUNC(cmd_allowauth)
2451 {
2452 struct userNode *target;
2453 struct handle_info *hi;
2454 unsigned int n;
2455
2456 NICKSERV_MIN_PARMS(2);
2457 if (!(target = GetUserH(argv[1]))) {
2458 reply("MSG_NICK_UNKNOWN", argv[1]);
2459 return 0;
2460 }
2461 if (target->handle_info) {
2462 reply("NSMSG_USER_PREV_AUTH", target->nick);
2463 return 0;
2464 }
2465 if (IsStamped(target)) {
2466 /* Unauthenticated users might still have been stamped
2467 previously and could therefore have a hidden host;
2468 do not allow them to authenticate to an account. */
2469 reply("NSMSG_USER_PREV_STAMP", target->nick);
2470 return 0;
2471 }
2472 if (argc == 2)
2473 hi = NULL;
2474 else if (!(hi = get_handle_info(argv[2]))) {
2475 reply("MSG_HANDLE_UNKNOWN", argv[2]);
2476 return 0;
2477 }
2478 if (hi) {
2479 if (hi->opserv_level > user->handle_info->opserv_level) {
2480 reply("MSG_USER_OUTRANKED", hi->handle);
2481 return 0;
2482 }
2483 if (((hi->flags & (HI_FLAG_SUPPORT_HELPER|HI_FLAG_NETWORK_HELPER))
2484 || (hi->opserv_level > 0))
2485 && ((argc < 4) || irccasecmp(argv[3], "staff"))) {
2486 reply("NSMSG_ALLOWAUTH_STAFF", hi->handle);
2487 return 0;
2488 }
2489 dict_insert(nickserv_allow_auth_dict, target->nick, hi);
2490 reply("NSMSG_AUTH_ALLOWED", target->nick, hi->handle);
2491 send_message(target, nickserv, "NSMSG_AUTH_ALLOWED_MSG", hi->handle, hi->handle);
2492 if (nickserv_conf.email_enabled)
2493 send_message(target, nickserv, "NSMSG_AUTH_ALLOWED_EMAIL");
2494 } else {
2495 if (dict_remove(nickserv_allow_auth_dict, target->nick))
2496 reply("NSMSG_AUTH_NORMAL_ONLY", target->nick);
2497 else
2498 reply("NSMSG_AUTH_UNSPECIAL", target->nick);
2499 }
2500 for (n=0; n<allowauth_func_used; n++)
2501 allowauth_func_list[n](user, target, hi, allowauth_func_list_extra[n]);
2502 return 1;
2503 }
2504
2505 static NICKSERV_FUNC(cmd_authcookie)
2506 {
2507 struct handle_info *hi;
2508
2509 NICKSERV_MIN_PARMS(2);
2510 if (user->handle_info) {
2511 reply("NSMSG_ALREADY_AUTHED", user->handle_info->handle);
2512 return 0;
2513 }
2514 if (IsStamped(user)) {
2515 /* Unauthenticated users might still have been stamped
2516 previously and could therefore have a hidden host;
2517 do not allow them to authenticate to an account. */
2518 reply("NSMSG_STAMPED_AUTHCOOKIE");
2519 return 0;
2520 }
2521 if (!(hi = get_handle_info(argv[1]))) {
2522 reply("MSG_HANDLE_UNKNOWN", argv[1]);
2523 return 0;
2524 }
2525 if (!hi->email_addr) {
2526 reply("MSG_SET_EMAIL_ADDR");
2527 return 0;
2528 }
2529 nickserv_make_cookie(user, hi, ALLOWAUTH, NULL, 0);
2530 return 1;
2531 }
2532
2533 static NICKSERV_FUNC(cmd_delcookie)
2534 {
2535 struct handle_info *hi;
2536
2537 hi = user->handle_info;
2538 if (!hi->cookie) {
2539 reply("NSMSG_NO_COOKIE");
2540 return 0;
2541 }
2542 switch (hi->cookie->type) {
2543 case ACTIVATION:
2544 case EMAIL_CHANGE:
2545 reply("NSMSG_MUST_TIME_OUT");
2546 break;
2547 default:
2548 nickserv_eat_cookie(hi->cookie);
2549 reply("NSMSG_ATE_COOKIE");
2550 break;
2551 }
2552 return 1;
2553 }
2554
2555 static NICKSERV_FUNC(cmd_odelcookie)
2556 {
2557 struct handle_info *hi;
2558
2559 NICKSERV_MIN_PARMS(2);
2560
2561 if (!(hi = get_victim_oper(user, argv[1])))
2562 return 0;
2563
2564 if (!hi->cookie) {
2565 reply("NSMSG_NO_COOKIE_FOREIGN", hi->handle);
2566 return 0;
2567 }
2568
2569 switch (hi->cookie->type) {
2570 case ACTIVATION:
2571 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2572 #ifdef WITH_LDAP
2573 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2574 int rc;
2575 if((rc = ldap_do_modify(hi->handle, hi->cookie->data, NULL)) != LDAP_SUCCESS) {
2576 /* Falied to update password in ldap, but still
2577 * updated it here.. what should we do? */
2578 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2579 return 0;
2580 }
2581 }
2582 #endif
2583 if (nickserv_conf.sync_log)
2584 SyncLog("ACCOUNTACC %s", hi->handle);
2585 break;
2586 case PASSWORD_CHANGE:
2587 break;
2588 case EMAIL_CHANGE:
2589 break;
2590 case ALLOWAUTH:
2591 break;
2592 default:
2593 reply("NSMSG_BAD_COOKIE_TYPE", hi->cookie->type);
2594 log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d for account %s.", hi->cookie->type, hi->handle);
2595 break;
2596 }
2597
2598 nickserv_eat_cookie(hi->cookie);
2599 reply("NSMSG_ATE_FOREIGN_COOKIE", hi->handle);
2600
2601 return 1;
2602 }
2603
2604 static NICKSERV_FUNC(cmd_resetpass)
2605 {
2606 struct handle_info *hi;
2607 char crypted[MD5_CRYPT_LENGTH];
2608 int weblink;
2609
2610 NICKSERV_MIN_PARMS(3);
2611 if(argc >= 4 && !strcmp(argv[3], "WEBLINK"))
2612 weblink = 1;
2613 else
2614 weblink = 0;
2615 if (user->handle_info) {
2616 reply("NSMSG_ALREADY_AUTHED", user->handle_info->handle);
2617 return 0;
2618 }
2619 if (IsStamped(user)) {
2620 /* Unauthenticated users might still have been stamped
2621 previously and could therefore have a hidden host;
2622 do not allow them to activate an account. */
2623 reply("NSMSG_STAMPED_RESETPASS");
2624 return 0;
2625 }
2626 if (!(hi = get_handle_info(argv[1]))) {
2627 reply("MSG_HANDLE_UNKNOWN", argv[1]);
2628 return 0;
2629 }
2630 if (!hi->email_addr) {
2631 reply("MSG_SET_EMAIL_ADDR");
2632 return 0;
2633 }
2634 cryptpass(argv[2], crypted);
2635 argv[2] = "****";
2636 nickserv_make_cookie(user, hi, PASSWORD_CHANGE, crypted, weblink);
2637 return 1;
2638 }
2639
2640 static NICKSERV_FUNC(cmd_cookie)
2641 {
2642 struct handle_info *hi;
2643 const char *cookie;
2644
2645 if ((argc == 2) && (hi = user->handle_info) && hi->cookie && (hi->cookie->type == EMAIL_CHANGE)) {
2646 cookie = argv[1];
2647 } else {
2648 NICKSERV_MIN_PARMS(3);
2649 if (!(hi = get_handle_info(argv[1]))) {
2650 reply("MSG_HANDLE_UNKNOWN", argv[1]);
2651 return 0;
2652 }
2653 cookie = argv[2];
2654 }
2655
2656 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
2657 reply("NSMSG_HANDLE_SUSPENDED");
2658 return 0;
2659 }
2660
2661 if (!hi->cookie) {
2662 reply("NSMSG_NO_COOKIE");
2663 return 0;
2664 }
2665
2666 /* Check validity of operation before comparing cookie to
2667 * prohibit guessing by authed users. */
2668 if (user->handle_info
2669 && (hi->cookie->type != EMAIL_CHANGE)
2670 && (hi->cookie->type != PASSWORD_CHANGE)) {
2671 reply("NSMSG_CANNOT_COOKIE");
2672 return 0;
2673 }
2674
2675 if (strcmp(cookie, hi->cookie->cookie)) {
2676 reply("NSMSG_BAD_COOKIE");
2677 return 0;
2678 }
2679
2680 switch (hi->cookie->type) {
2681 case ACTIVATION:
2682 #ifdef WITH_LDAP
2683 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2684 int rc;
2685 if((rc = ldap_do_modify(hi->handle, hi->cookie->data, NULL)) != LDAP_SUCCESS) {
2686 /* Falied to update email in ldap, but still
2687 * updated it here.. what should we do? */
2688 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2689 return 0;
2690 }
2691 }
2692 #endif
2693 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2694 set_user_handle_info(user, hi, 1);
2695 reply("NSMSG_HANDLE_ACTIVATED");
2696 if (nickserv_conf.sync_log)
2697 SyncLog("ACCOUNTACC %s", hi->handle);
2698 break;
2699 case PASSWORD_CHANGE:
2700 #ifdef WITH_LDAP
2701 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2702 int rc;
2703 if((rc = ldap_do_modify(hi->handle, hi->cookie->data, NULL)) != LDAP_SUCCESS) {
2704 /* Falied to update email in ldap, but still
2705 * updated it here.. what should we do? */
2706 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2707 return 0;
2708 }
2709 }
2710 #endif
2711 set_user_handle_info(user, hi, 1);
2712 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2713 reply("NSMSG_PASSWORD_CHANGED");
2714 if (nickserv_conf.sync_log)
2715 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
2716 break;
2717 case EMAIL_CHANGE:
2718 #ifdef WITH_LDAP
2719 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2720 int rc;
2721 if((rc = ldap_do_modify(hi->handle, NULL, hi->cookie->data)) != LDAP_SUCCESS) {
2722 /* Falied to update email in ldap, but still
2723 * updated it here.. what should we do? */
2724 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc));
2725 return 0;
2726 }
2727 }
2728 #endif
2729 if (!hi->email_addr && nickserv_conf.sync_log) {
2730 /*
2731 * This should only happen if an OREGISTER was sent. Require
2732 * email must be enabled! - SiRVulcaN
2733 */
2734 if (nickserv_conf.sync_log)
2735 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, hi->cookie->data, user->info);
2736 }
2737
2738 nickserv_set_email_addr(hi, hi->cookie->data);
2739 reply("NSMSG_EMAIL_CHANGED");
2740 if (nickserv_conf.sync_log)
2741 SyncLog("EMAILCHANGE %s %s", hi->handle, hi->cookie->data);
2742 break;
2743 case ALLOWAUTH: {
2744 char *mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
2745 set_user_handle_info(user, hi, 1);
2746 nickserv_addmask(user, hi, mask);
2747 reply("NSMSG_AUTH_SUCCESS");
2748 free(mask);
2749 break;
2750 }
2751 default:
2752 reply("NSMSG_BAD_COOKIE_TYPE", hi->cookie->type);
2753 log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d for account %s.", hi->cookie->type, hi->handle);
2754 break;
2755 }
2756
2757 nickserv_eat_cookie(hi->cookie);
2758
2759 process_adduser_pending(user);
2760
2761 return 1;
2762 }
2763
2764 static NICKSERV_FUNC(cmd_oregnick) {
2765 const char *nick;
2766 struct handle_info *target;
2767 struct nick_info *ni;
2768
2769 NICKSERV_MIN_PARMS(3);
2770 if (!(target = modcmd_get_handle_info(user, argv[1])))
2771 return 0;
2772 nick = argv[2];
2773 if (!is_registerable_nick(nick)) {
2774 reply("NSMSG_BAD_NICK", nick);
2775 return 0;
2776 }
2777 ni = dict_find(nickserv_nick_dict, nick, NULL);
2778 if (ni) {
2779 reply("NSMSG_NICK_EXISTS", nick);
2780 return 0;
2781 }
2782 register_nick(nick, target);
2783 reply("NSMSG_OREGNICK_SUCCESS", nick, target->handle);
2784 return 1;
2785 }
2786
2787 static NICKSERV_FUNC(cmd_regnick) {
2788 unsigned n;
2789 struct nick_info *ni;
2790
2791 if (!is_registerable_nick(user->nick)) {
2792 reply("NSMSG_BAD_NICK", user->nick);
2793 return 0;
2794 }
2795 /* count their nicks, see if it's too many */
2796 for (n=0,ni=user->handle_info->nicks; ni; n++,ni=ni->next) ;
2797 if (n >= nickserv_conf.nicks_per_handle) {
2798 reply("NSMSG_TOO_MANY_NICKS");
2799 return 0;
2800 }
2801 ni = dict_find(nickserv_nick_dict, user->nick, NULL);
2802 if (ni) {
2803 reply("NSMSG_NICK_EXISTS", user->nick);
2804 return 0;
2805 }
2806 register_nick(user->nick, user->handle_info);
2807 reply("NSMSG_REGNICK_SUCCESS", user->nick);
2808 return 1;
2809 }
2810
2811 static NICKSERV_FUNC(cmd_pass)
2812 {
2813 struct handle_info *hi;
2814 char *old_pass, *new_pass;
2815 char crypted[MD5_CRYPT_LENGTH+1];
2816 #ifdef WITH_LDAP
2817 int ldap_result;
2818 #endif
2819
2820 NICKSERV_MIN_PARMS(3);
2821 hi = user->handle_info;
2822 old_pass = argv[1];
2823 new_pass = argv[2];
2824 argv[2] = "****";
2825 if (!is_secure_password(hi->handle, new_pass, user)) return 0;
2826
2827 #ifdef WITH_LDAP
2828 if(nickserv_conf.ldap_enable) {
2829 ldap_result = ldap_check_auth(hi->handle, old_pass);
2830 if(ldap_result != LDAP_SUCCESS) {
2831 if(ldap_result == LDAP_INVALID_CREDENTIALS)
2832 reply("NSMSG_PASSWORD_INVALID");
2833 else
2834 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result));
2835 return 0;
2836 }
2837 }else
2838 #endif
2839 if (!checkpass(old_pass, hi->passwd)) {
2840 argv[1] = "BADPASS";
2841 reply("NSMSG_PASSWORD_INVALID");
2842 return 0;
2843 }
2844 cryptpass(new_pass, crypted);
2845 #ifdef WITH_LDAP
2846 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2847 int rc;
2848 if((rc = ldap_do_modify(hi->handle, crypted, NULL)) != LDAP_SUCCESS) {
2849 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2850 return 0;
2851 }
2852 }
2853 #endif
2854 //cryptpass(new_pass, hi->passwd);
2855 strcpy(hi->passwd, crypted);
2856 if (nickserv_conf.sync_log)
2857 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
2858 argv[1] = "****";
2859 reply("NSMSG_PASS_SUCCESS");
2860 return 1;
2861 }
2862
2863 static int
2864 nickserv_addmask(struct userNode *user, struct handle_info *hi, const char *mask)
2865 {
2866 unsigned int i;
2867 char *new_mask = canonicalize_hostmask(strdup(mask));
2868 for (i=0; i<hi->masks->used; i++) {
2869 if (!irccasecmp(new_mask, hi->masks->list[i])) {
2870 send_message(user, nickserv, "NSMSG_ADDMASK_ALREADY", new_mask);
2871 free(new_mask);
2872 return 0;
2873 }
2874 }
2875 string_list_append(hi->masks, new_mask);
2876 send_message(user, nickserv, "NSMSG_ADDMASK_SUCCESS", new_mask);
2877 return 1;
2878 }
2879
2880 static NICKSERV_FUNC(cmd_addmask)
2881 {
2882 if (argc < 2) {
2883 char *mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
2884 int res = nickserv_addmask(user, user->handle_info, mask);
2885 free(mask);
2886 return res;
2887 } else {
2888 if (!is_gline(argv[1])) {
2889 reply("NSMSG_MASK_INVALID", argv[1]);
2890 return 0;
2891 }
2892 return nickserv_addmask(user, user->handle_info, argv[1]);
2893 }
2894 }
2895
2896 static NICKSERV_FUNC(cmd_oaddmask)
2897 {
2898 struct handle_info *hi;
2899
2900 NICKSERV_MIN_PARMS(3);
2901 if (!(hi = get_victim_oper(user, argv[1])))
2902 return 0;
2903 return nickserv_addmask(user, hi, argv[2]);
2904 }
2905
2906 static int
2907 nickserv_delmask(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, const char *del_mask, int force)
2908 {
2909 unsigned int i;
2910 for (i=0; i<hi->masks->used; i++) {
2911 if (!strcmp(del_mask, hi->masks->list[i])) {
2912 char *old_mask = hi->masks->list[i];
2913 if (hi->masks->used == 1 && !force) {
2914 reply("NSMSG_DELMASK_NOTLAST");
2915 return 0;
2916 }
2917 hi->masks->list[i] = hi->masks->list[--hi->masks->used];
2918 reply("NSMSG_DELMASK_SUCCESS", old_mask);
2919 free(old_mask);
2920 return 1;
2921 }
2922 }
2923 reply("NSMSG_DELMASK_NOT_FOUND");
2924 return 0;
2925 }
2926
2927 static NICKSERV_FUNC(cmd_delmask)
2928 {
2929 NICKSERV_MIN_PARMS(2);
2930 return nickserv_delmask(cmd, user, user->handle_info, argv[1], 0);
2931 }
2932
2933 static NICKSERV_FUNC(cmd_odelmask)
2934 {
2935 struct handle_info *hi;
2936 NICKSERV_MIN_PARMS(3);
2937 if (!(hi = get_victim_oper(user, argv[1])))
2938 return 0;
2939 return nickserv_delmask(cmd, user, hi, argv[2], 1);
2940 }
2941
2942 static int
2943 nickserv_addsslfp(struct userNode *user, struct handle_info *hi, const char *sslfp)
2944 {
2945 unsigned int i;
2946 char *new_sslfp = strdup(sslfp);
2947 for (i=0; i<hi->sslfps->used; i++) {
2948 if (!irccasecmp(new_sslfp, hi->sslfps->list[i])) {
2949 send_message(user, nickserv, "NSMSG_ADDSSLFP_ALREADY", new_sslfp);
2950 free(new_sslfp);
2951 return 0;
2952 }
2953 }
2954 string_list_append(hi->sslfps, new_sslfp);
2955 send_message(user, nickserv, "NSMSG_ADDSSLFP_SUCCESS", new_sslfp);
2956 return 1;
2957 }
2958
2959 static NICKSERV_FUNC(cmd_addsslfp)
2960 {
2961 NICKSERV_MIN_PARMS((user->sslfp ? 1 : 2));
2962 if ((argc < 2) && (user->sslfp)) {
2963 int res = nickserv_addsslfp(user, user->handle_info, user->sslfp);
2964 return res;
2965 } else {
2966 return nickserv_addsslfp(user, user->handle_info, argv[1]);
2967 }
2968 }
2969
2970 static NICKSERV_FUNC(cmd_oaddsslfp)
2971 {
2972 struct handle_info *hi;
2973
2974 NICKSERV_MIN_PARMS(3);
2975 if (!(hi = get_victim_oper(user, argv[1])))
2976 return 0;
2977 return nickserv_addsslfp(user, hi, argv[2]);
2978 }
2979
2980 static int
2981 nickserv_delsslfp(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, const char *del_sslfp)
2982 {
2983 unsigned int i;
2984 for (i=0; i<hi->sslfps->used; i++) {
2985 if (!irccasecmp(del_sslfp, hi->sslfps->list[i])) {
2986 char *old_sslfp = hi->sslfps->list[i];
2987 hi->sslfps->list[i] = hi->sslfps->list[--hi->sslfps->used];
2988 reply("NSMSG_DELSSLFP_SUCCESS", old_sslfp);
2989 free(old_sslfp);
2990 return 1;
2991 }
2992 }
2993 reply("NSMSG_DELSSLFP_NOT_FOUND");
2994 return 0;
2995 }
2996
2997 static NICKSERV_FUNC(cmd_delsslfp)
2998 {
2999 NICKSERV_MIN_PARMS((user->sslfp ? 1 : 2));
3000 if ((argc < 2) && (user->sslfp)) {
3001 return nickserv_delsslfp(cmd, user, user->handle_info, user->sslfp);
3002 } else {
3003 return nickserv_delsslfp(cmd, user, user->handle_info, argv[1]);
3004 }
3005 }
3006
3007 static NICKSERV_FUNC(cmd_odelsslfp)
3008 {
3009 struct handle_info *hi;
3010 NICKSERV_MIN_PARMS(3);
3011 if (!(hi = get_victim_oper(user, argv[1])))
3012 return 0;
3013 return nickserv_delsslfp(cmd, user, hi, argv[2]);
3014 }
3015
3016 int
3017 nickserv_modify_handle_flags(struct userNode *user, struct userNode *bot, const char *str, unsigned long *padded, unsigned long *premoved) {
3018 unsigned int nn, add = 1, pos;
3019 unsigned long added, removed, flag;
3020
3021 for (added=removed=nn=0; str[nn]; nn++) {
3022 switch (str[nn]) {
3023 case '+': add = 1; break;
3024 case '-': add = 0; break;
3025 default:
3026 if (!(pos = handle_inverse_flags[(unsigned char)str[nn]])) {
3027 send_message(user, bot, "NSMSG_INVALID_FLAG", str[nn]);
3028 return 0;
3029 }
3030 if (user && (user->handle_info->opserv_level < flag_access_levels[pos-1])) {
3031 /* cheesy avoidance of looking up the flag name.. */
3032 send_message(user, bot, "NSMSG_FLAG_PRIVILEGED", str[nn]);
3033 return 0;
3034 }
3035 flag = 1 << (pos - 1);
3036 if (add)
3037 added |= flag, removed &= ~flag;
3038 else
3039 removed |= flag, added &= ~flag;
3040 break;
3041 }
3042 }
3043 *padded = added;
3044 *premoved = removed;
3045 return 1;
3046 }
3047
3048 static int
3049 nickserv_apply_flags(struct userNode *user, struct handle_info *hi, const char *flags)
3050 {
3051 unsigned long before, after, added, removed;
3052 struct userNode *uNode;
3053
3054 before = hi->flags & (HI_FLAG_SUPPORT_HELPER|HI_FLAG_NETWORK_HELPER);
3055 if (!nickserv_modify_handle_flags(user, nickserv, flags, &added, &removed))
3056 return 0;
3057 hi->flags = (hi->flags | added) & ~removed;
3058 after = hi->flags & (HI_FLAG_SUPPORT_HELPER|HI_FLAG_NETWORK_HELPER);
3059
3060 /* Strip helping flag if they're only a support helper and not
3061 * currently in #support. */
3062 if (HANDLE_FLAGGED(hi, HELPING) && (after == HI_FLAG_SUPPORT_HELPER)) {
3063 struct channelList *schannels;
3064 unsigned int ii;
3065 schannels = chanserv_support_channels();
3066 for (ii = 0; ii < schannels->used; ++ii)
3067 if (find_handle_in_channel(schannels->list[ii], hi, NULL))
3068 break;
3069 if (ii == schannels->used)
3070 HANDLE_CLEAR_FLAG(hi, HELPING);
3071 }
3072
3073 if (after && !before) {
3074 /* Add user to current helper list. */
3075 for (uNode = hi->users; uNode; uNode = uNode->next_authed)
3076 userList_append(&curr_helpers, uNode);
3077 } else if (!after && before) {
3078 /* Remove user from current helper list. */
3079 for (uNode = hi->users; uNode; uNode = uNode->next_authed)
3080 userList_remove(&curr_helpers, uNode);
3081 }
3082
3083 return 1;
3084 }
3085
3086 static void
3087 set_list(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, int override)
3088 {
3089 option_func_t *opt;
3090 unsigned int i;
3091 char *set_display[] = {
3092 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
3093 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
3094 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
3095 };
3096
3097 reply("NSMSG_SETTING_LIST");
3098 reply("NSMSG_SETTING_LIST_HEADER");
3099
3100 /* Do this so options are presented in a consistent order. */
3101 for (i = 0; i < ArrayLength(set_display); ++i)
3102 if ((opt = dict_find(nickserv_opt_dict, set_display[i], NULL)))
3103 opt(cmd, user, hi, override, 0, NULL);
3104 reply("NSMSG_SETTING_LIST_END");
3105 }
3106
3107 static NICKSERV_FUNC(cmd_set)
3108 {
3109 struct handle_info *hi;
3110 option_func_t *opt;
3111
3112 hi = user->handle_info;
3113 if (argc < 2) {
3114 set_list(cmd, user, hi, 0);
3115 return 1;
3116 }
3117 if (!(opt = dict_find(nickserv_opt_dict, argv[1], NULL))) {
3118 reply("NSMSG_INVALID_OPTION", argv[1]);
3119 return 0;
3120 }
3121 return opt(cmd, user, hi, 0, argc-1, argv+1);
3122 }
3123
3124 static NICKSERV_FUNC(cmd_oset)
3125 {
3126 struct handle_info *hi;
3127 option_func_t *opt;
3128
3129 NICKSERV_MIN_PARMS(2);
3130
3131 if (!(hi = get_victim_oper(user, argv[1])))
3132 return 0;
3133
3134 if (argc < 3) {
3135 set_list(cmd, user, hi, 0);
3136 return 1;
3137 }
3138
3139 if (!(opt = dict_find(nickserv_opt_dict, argv[2], NULL))) {
3140 reply("NSMSG_INVALID_OPTION", argv[2]);
3141 return 0;
3142 }
3143
3144 return opt(cmd, user, hi, 1, argc-2, argv+2);
3145 }
3146
3147 static OPTION_FUNC(opt_info)
3148 {
3149 const char *info;
3150 if (argc > 1) {
3151 if ((argv[1][0] == '*') && (argv[1][1] == 0)) {
3152 free(hi->infoline);
3153 hi->infoline = NULL;
3154 } else {
3155 hi->infoline = strdup(unsplit_string(argv+1, argc-1, NULL));
3156 }
3157 }
3158
3159 info = hi->infoline ? hi->infoline : user_find_message(user, "MSG_NONE");
3160 reply("NSMSG_SET_INFO", info);
3161 return 1;
3162 }
3163
3164 static OPTION_FUNC(opt_width)
3165 {
3166 if (argc > 1)
3167 hi->screen_width = strtoul(argv[1], NULL, 0);
3168
3169 if ((hi->screen_width > 0) && (hi->screen_width < MIN_LINE_SIZE))
3170 hi->screen_width = MIN_LINE_SIZE;
3171 else if (hi->screen_width > MAX_LINE_SIZE)
3172 hi->screen_width = MAX_LINE_SIZE;
3173
3174 reply("NSMSG_SET_WIDTH", hi->screen_width);
3175 return 1;
3176 }
3177
3178 static OPTION_FUNC(opt_tablewidth)
3179 {
3180 if (argc > 1)
3181 hi->table_width = strtoul(argv[1], NULL, 0);
3182
3183 if ((hi->table_width > 0) && (hi->table_width < MIN_LINE_SIZE))
3184 hi->table_width = MIN_LINE_SIZE;
3185 else if (hi->screen_width > MAX_LINE_SIZE)
3186 hi->table_width = MAX_LINE_SIZE;
3187
3188 reply("NSMSG_SET_TABLEWIDTH", hi->table_width);
3189 return 1;
3190 }
3191
3192 static OPTION_FUNC(opt_color)
3193 {
3194 if (argc > 1) {
3195 if (enabled_string(argv[1]))
3196 HANDLE_SET_FLAG(hi, MIRC_COLOR);
3197 else if (disabled_string(argv[1]))
3198 HANDLE_CLEAR_FLAG(hi, MIRC_COLOR);
3199 else {
3200 reply("MSG_INVALID_BINARY", argv[1]);
3201 return 0;
3202 }
3203 }
3204
3205 reply("NSMSG_SET_COLOR", user_find_message(user, HANDLE_FLAGGED(hi, MIRC_COLOR) ? "MSG_ON" : "MSG_OFF"));
3206 return 1;
3207 }
3208
3209 static OPTION_FUNC(opt_privmsg)
3210 {
3211 if (argc > 1) {
3212 if (enabled_string(argv[1]))
3213 HANDLE_SET_FLAG(hi, USE_PRIVMSG);
3214 else if (disabled_string(argv[1]))
3215 HANDLE_CLEAR_FLAG(hi, USE_PRIVMSG);
3216 else {
3217 reply("MSG_INVALID_BINARY", argv[1]);
3218 return 0;
3219 }
3220 }
3221
3222 reply("NSMSG_SET_PRIVMSG", user_find_message(user, HANDLE_FLAGGED(hi, USE_PRIVMSG) ? "MSG_ON" : "MSG_OFF"));
3223 return 1;
3224 }
3225
3226 static OPTION_FUNC(opt_autohide)
3227 {
3228 if (argc > 1) {
3229 if (enabled_string(argv[1]))
3230 HANDLE_SET_FLAG(hi, AUTOHIDE);
3231 else if (disabled_string(argv[1]))
3232 HANDLE_CLEAR_FLAG(hi, AUTOHIDE);
3233 else {
3234 reply("MSG_INVALID_BINARY", argv[1]);
3235 return 0;
3236 }
3237 }
3238
3239 reply("NSMSG_SET_AUTOHIDE", user_find_message(user, HANDLE_FLAGGED(hi, AUTOHIDE) ? "MSG_ON" : "MSG_OFF"));
3240 return 1;
3241 }
3242
3243 static OPTION_FUNC(opt_style)
3244 {
3245 char *style;
3246
3247 if (argc > 1) {
3248 if (!irccasecmp(argv[1], "Clean"))
3249 hi->userlist_style = HI_STYLE_CLEAN;
3250 else if (!irccasecmp(argv[1], "Advanced"))
3251 hi->userlist_style = HI_STYLE_ADVANCED;
3252 else if (!irccasecmp(argv[1], "Classic"))
3253 hi->userlist_style = HI_STYLE_CLASSIC;
3254 else /* Default to normal */
3255 hi->userlist_style = HI_STYLE_NORMAL;
3256 } /* TODO: give error if unknow style is chosen */
3257
3258 switch (hi->userlist_style) {
3259 case HI_STYLE_ADVANCED:
3260 style = "Advanced";
3261 break;
3262 case HI_STYLE_CLASSIC:
3263 style = "Classic";
3264 break;
3265 case HI_STYLE_CLEAN:
3266 style = "Clean";
3267 break;
3268 case HI_STYLE_NORMAL:
3269 default:
3270 style = "Normal";
3271 }
3272
3273 reply("NSMSG_SET_STYLE", style);
3274 return 1;
3275 }
3276
3277 static OPTION_FUNC(opt_announcements)
3278 {
3279 const char *choice;
3280
3281 if (argc > 1) {
3282 if (enabled_string(argv[1]))
3283 hi->announcements = 'y';
3284 else if (disabled_string(argv[1]))
3285 hi->announcements = 'n';
3286 else if (!strcmp(argv[1], "?") || !irccasecmp(argv[1], "default"))
3287 hi->announcements = '?';
3288 else {
3289 reply("NSMSG_INVALID_ANNOUNCE", argv[1]);
3290 return 0;
3291 }
3292 }
3293
3294 switch (hi->announcements) {
3295 case 'y': choice = user_find_message(user, "MSG_ON"); break;
3296 case 'n': choice = user_find_message(user, "MSG_OFF"); break;
3297 case '?': choice = "default"; break;
3298 default: choice = "unknown"; break;
3299 }
3300 reply("NSMSG_SET_ANNOUNCEMENTS", choice);
3301 return 1;
3302 }
3303
3304 static OPTION_FUNC(opt_password)
3305 {
3306 char crypted[MD5_CRYPT_LENGTH+1];
3307 if(argc < 2) {
3308 return 0;
3309 }
3310 if (!override) {
3311 reply("NSMSG_USE_CMD_PASS");
3312 return 0;
3313 }
3314
3315 cryptpass(argv[1], crypted);
3316 #ifdef WITH_LDAP
3317 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
3318 int rc;
3319 if((rc = ldap_do_modify(hi->handle, crypted, NULL)) != LDAP_SUCCESS) {
3320 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
3321 return 0;
3322 }
3323 }
3324 #endif
3325 strcpy(hi->passwd, crypted);
3326 if (nickserv_conf.sync_log)
3327 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
3328
3329 reply("NSMSG_SET_PASSWORD", "***");
3330 return 1;
3331 }
3332
3333 static OPTION_FUNC(opt_flags)
3334 {
3335 char flags[33];
3336 unsigned int ii, flen;
3337
3338 if (!override) {
3339 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3340 return 0;
3341 }
3342
3343 if (argc > 1)
3344 nickserv_apply_flags(user, hi, argv[1]);
3345
3346 for (ii = flen = 0; handle_flags[ii]; ii++)
3347 if (hi->flags & (1 << ii))
3348 flags[flen++] = handle_flags[ii];
3349 flags[flen] = '\0';
3350 if (hi->flags)
3351 reply("NSMSG_SET_FLAGS", flags);
3352 else
3353 reply("NSMSG_SET_FLAGS", user_find_message(user, "MSG_NONE"));
3354 return 1;
3355 }
3356
3357 static OPTION_FUNC(opt_email)
3358 {
3359 if (argc > 1) {
3360 const char *str;
3361 if (!valid_email(argv[1])) {
3362 reply("NSMSG_BAD_EMAIL_ADDR");
3363 return 0;
3364 }
3365 if ((str = mail_prohibited_address(argv[1]))) {
3366 reply("NSMSG_EMAIL_PROHIBITED", argv[1], str);
3367 return 0;
3368 }
3369 if (hi->email_addr && !irccasecmp(hi->email_addr, argv[1]))
3370 reply("NSMSG_EMAIL_SAME");
3371 else if (!override)
3372 nickserv_make_cookie(user, hi, EMAIL_CHANGE, argv[1], 0);
3373 else {
3374 #ifdef WITH_LDAP
3375 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
3376 int rc;
3377 if((rc = ldap_do_modify(hi->handle, NULL, argv[1])) != LDAP_SUCCESS) {
3378 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
3379 return 0;
3380 }
3381 }
3382 #endif
3383 nickserv_set_email_addr(hi, argv[1]);
3384 if (hi->cookie)
3385 nickserv_eat_cookie(hi->cookie);
3386 reply("NSMSG_SET_EMAIL", visible_email_addr(user, hi));
3387 }
3388 } else
3389 reply("NSMSG_SET_EMAIL", visible_email_addr(user, hi));
3390 return 1;
3391 }
3392
3393 static OPTION_FUNC(opt_maxlogins)
3394 {
3395 unsigned char maxlogins;
3396 if (argc > 1) {
3397 maxlogins = strtoul(argv[1], NULL, 0);
3398 if ((maxlogins > nickserv_conf.hard_maxlogins) && !override) {
3399 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf.hard_maxlogins);
3400 return 0;
3401 }
3402 hi->maxlogins = maxlogins;
3403 }
3404 maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
3405 reply("NSMSG_SET_MAXLOGINS", maxlogins);
3406 return 1;
3407 }
3408
3409 static OPTION_FUNC(opt_advanced)
3410 {
3411 if (argc > 1) {
3412 if (enabled_string(argv[1]))
3413 HANDLE_SET_FLAG(hi, ADVANCED);
3414 else if (disabled_string(argv[1]))
3415 HANDLE_CLEAR_FLAG(hi, ADVANCED);
3416 else {
3417 reply("MSG_INVALID_BINARY", argv[1]);
3418 return 0;
3419 }
3420 }
3421
3422 reply("NSMSG_SET_ADVANCED", user_find_message(user, HANDLE_FLAGGED(hi, ADVANCED) ? "MSG_ON" : "MSG_OFF"));
3423 return 1;
3424 }
3425
3426 static OPTION_FUNC(opt_language)
3427 {
3428 struct language *lang;
3429 if (argc > 1) {
3430 lang = language_find(argv[1]);
3431 if (irccasecmp(lang->name, argv[1]))
3432 reply("NSMSG_LANGUAGE_NOT_FOUND", argv[1], lang->name);
3433 hi->language = lang;
3434 }
3435 reply("NSMSG_SET_LANGUAGE", hi->language->name);
3436 return 1;
3437 }
3438
3439 static OPTION_FUNC(opt_karma)
3440 {
3441 if (!override) {
3442 send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
3443 return 0;
3444 }
3445
3446 if (argc > 1) {
3447 if (argv[1][0] == '+' && isdigit(argv[1][1])) {
3448 hi->karma += strtoul(argv[1] + 1, NULL, 10);
3449 } else if (argv[1][0] == '-' && isdigit(argv[1][1])) {
3450 hi->karma -= strtoul(argv[1] + 1, NULL, 10);
3451 } else {
3452 send_message(user, nickserv, "NSMSG_INVALID_KARMA", argv[1]);
3453 }
3454 }
3455
3456 send_message(user, nickserv, "NSMSG_SET_KARMA", hi->karma);
3457 return 1;
3458 }
3459
3460 /* Called from opserv from cmd_access */
3461 int
3462 oper_try_set_access(struct userNode *user, struct userNode *bot, struct handle_info *target, unsigned int new_level) {
3463 if (!oper_has_access(user, bot, nickserv_conf.modoper_level, 0))
3464 return 0;
3465 if ((user->handle_info->opserv_level < target->opserv_level)
3466 || ((user->handle_info->opserv_level == target->opserv_level)
3467 && (user->handle_info->opserv_level < 1000))) {
3468 send_message(user, bot, "MSG_USER_OUTRANKED", target->handle);
3469 return 0;
3470 }
3471 if ((user->handle_info->opserv_level < new_level)
3472 || ((user->handle_info->opserv_level == new_level)
3473 && (user->handle_info->opserv_level < 1000))) {
3474 send_message(user, bot, "NSMSG_OPSERV_LEVEL_BAD");
3475 return 0;
3476 }
3477 if (user->handle_info == target) {
3478 send_message(user, bot, "MSG_STUPID_ACCESS_CHANGE");
3479 return 0;
3480 }
3481 #ifdef WITH_LDAP
3482 if(nickserv_conf.ldap_enable && *(nickserv_conf.ldap_oper_group_dn) && *(nickserv_conf.ldap_admin_dn)) {
3483 int rc;
3484 if(new_level > nickserv_conf.ldap_oper_group_level)
3485 rc = ldap_add2group(target->handle, nickserv_conf.ldap_oper_group_dn);
3486 else
3487 rc = ldap_delfromgroup(target->handle, nickserv_conf.ldap_oper_group_dn);
3488 if(rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS && rc != LDAP_NO_SUCH_ATTRIBUTE) {
3489 send_message(user, bot, "NSMSG_LDAP_FAIL", ldap_err2string(rc));
3490 return 0;
3491 }
3492 }
3493 if(nickserv_conf.ldap_enable && *(nickserv_conf.ldap_field_oslevel) && *(nickserv_conf.ldap_admin_dn)) {
3494 int rc;
3495 if((rc = ldap_do_oslevel(target->handle, new_level, target->opserv_level)) != LDAP_SUCCESS) {
3496 send_message(user, bot, "NSMSG_LDAP_FAIL", ldap_err2string(rc));
3497 return 0;
3498 }
3499 }
3500 #endif
3501 if (target->opserv_level == new_level)
3502 return 0;
3503 log_module(NS_LOG, LOG_INFO, "Account %s setting oper level for account %s to %d (from %d).",
3504 user->handle_info->handle, target->handle, new_level, target->opserv_level);
3505 target->opserv_level = new_level;
3506 return 1;
3507 }
3508
3509 static OPTION_FUNC(opt_level)
3510 {
3511 int res;
3512
3513 if (!override) {
3514 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3515 return 0;
3516 }
3517
3518 res = (argc > 1) ? oper_try_set_access(user, nickserv, hi, strtoul(argv[1], NULL, 0)) : 0;
3519 reply("NSMSG_SET_LEVEL", hi->opserv_level);
3520 return res;
3521 }
3522
3523 static OPTION_FUNC(opt_epithet)
3524 {
3525 if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_epithet_level, 0)) {
3526 char *epithet;
3527 struct userNode *target, *next_un;
3528
3529 if (!override) {
3530 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3531 return 0;
3532 }
3533
3534 epithet = unsplit_string(argv+1, argc-1, NULL);
3535
3536 if (hi->epithet)
3537 free(hi->epithet);
3538 if ((epithet[0] == '*') && !epithet[1])
3539 hi->epithet = NULL;
3540 else
3541 hi->epithet = strdup(epithet);
3542
3543 for (target = hi->users; target; target = next_un) {
3544 irc_swhois(nickserv, target, hi->epithet);
3545
3546 next_un = target->next_authed;
3547 }
3548 }
3549
3550 if (hi->epithet)
3551 reply("NSMSG_SET_EPITHET", hi->epithet);
3552 else
3553 reply("NSMSG_SET_EPITHET", user_find_message(user, "MSG_NONE"));
3554 return 1;
3555 }
3556
3557 static OPTION_FUNC(opt_title)
3558 {
3559 char *title;
3560 const char *none;
3561 char *sptr;
3562
3563 if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_title_level, 0)) {
3564 if (!override) {
3565 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3566 return 0;
3567 }
3568
3569 title = argv[1];
3570 if(!strcmp(title, "*")) {
3571 free(hi->fakehost);
3572 hi->fakehost = NULL;
3573 }
3574 else {
3575 if (strchr(title, '.')) {
3576 reply("NSMSG_TITLE_INVALID");
3577 return 0;
3578 }
3579 /* Alphanumeric titles only. */
3580 for(sptr = title; *sptr; sptr++) {
3581 if(!isalnum(*sptr) && *sptr != '-') {
3582 reply("NSMSG_TITLE_INVALID");
3583 return 0;
3584 }
3585 }
3586 if ((strlen(user->handle_info->handle) + strlen(title) +
3587 strlen(nickserv_conf.titlehost_suffix) + 2) > HOSTLEN) {
3588 reply("NSMSG_TITLE_TRUNCATED");
3589 return 0;
3590 }
3591 free(hi->fakehost);
3592 hi->fakehost = malloc(strlen(title)+2);
3593 hi->fakehost[0] = '.';
3594 strcpy(hi->fakehost+1, title);
3595 }
3596 apply_fakehost(hi);
3597 } else if (hi->fakehost && (hi->fakehost[0] == '.'))
3598 title = hi->fakehost + 1;
3599 else {
3600 /* If theres no title set then the default title will therefore
3601 be the first part of hidden_host in x3.conf, so for
3602 consistency with opt_fakehost we will print this here.
3603 This isnt actually used in P10, its just handled to keep from crashing... */
3604 char *hs, *hidden_suffix, *rest;
3605
3606 hs = conf_get_data("server/hidden_host", RECDB_QSTRING);
3607 hidden_suffix = strdup(hs);
3608
3609 /* Yes we do this twice */
3610 if((rest = strchr(hidden_suffix, '.')))
3611 {
3612 *rest = '\0';
3613 title = hidden_suffix;
3614 }
3615 else
3616 {
3617 /* A lame default if someone configured hidden_host to something lame */
3618 title = strdup("users");
3619 free(hidden_suffix);
3620 }
3621
3622 }
3623
3624 if (!title)
3625 none = user_find_message(user, "MSG_NONE");
3626 send_message(user, nickserv, "NSMSG_SET_TITLE", title ? title : none);
3627 return 1;
3628 }
3629
3630 int
3631 check_vhost(char *vhost, struct userNode *user, struct svccmd *cmd)
3632 {
3633 unsigned int y;
3634
3635 // check for a dot in the vhost
3636 if(strchr(vhost, '.') == NULL) {
3637 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost);
3638 return 0;
3639 }
3640
3641 // check for a @ in the vhost
3642 if(strchr(vhost, '@') != NULL) {
3643 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost);
3644 return 0;
3645 }
3646
3647 // check for denied words, inspired by monk at paki.sex
3648 for(y = 0; y < nickserv_conf.denied_fakehost_words->used; y++) {
3649 if(strstr(vhost, nickserv_conf.denied_fakehost_words->list[y]) != NULL) {
3650 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost, nickserv_conf.denied_fakehost_words->list[y]);
3651 return 0;
3652 }
3653 }
3654
3655 // check for ircu's HOSTLEN length.
3656 if(strlen(vhost) >= HOSTLEN) {
3657 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost);
3658 return 0;
3659 }
3660
3661 /* This can be handled by the regex now if desired.
3662 if (vhost[strspn(vhost, "0123456789.")]) {
3663 hostname = vhost + strlen(vhost);
3664 for (depth = 1; depth && (hostname > vhost); depth--) {
3665 hostname--;
3666 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3667 }
3668
3669 if (*hostname == '.') hostname++; * advance past last dot we saw *
3670 if(strlen(hostname) > 4) {
3671 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3672 return 0;
3673 }
3674 }
3675 */
3676 /* test either regex or as valid handle */
3677 if (nickserv_conf.valid_fakehost_regex_set) {
3678 int err = regexec(&nickserv_conf.valid_fakehost_regex, vhost, 0, 0, 0);
3679 if (err) {
3680 char buff[256];
3681 buff[regerror(err, &nickserv_conf.valid_fakehost_regex, buff, sizeof(buff))] = 0;
3682 log_module(NS_LOG, LOG_INFO, "regexec error: %s (%d)", buff, err);
3683 }
3684 if(err == REG_NOMATCH) {
3685 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost);
3686 return 0;
3687 }
3688 }
3689
3690
3691 return 1;
3692 }
3693
3694 static OPTION_FUNC(opt_fakehost)
3695 {
3696 const char *fake;
3697
3698 if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_fakehost_level, 0)) {
3699 if (!override) {
3700 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3701 return 0;
3702 }
3703
3704 fake = argv[1];
3705 if ((strlen(fake) > HOSTLEN) || (fake[0] == '.')) {
3706 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN);
3707 return 0;
3708 }
3709 if (!strcmp(fake, "*")) {
3710 if(hi->fakehost) {
3711 free(hi->fakehost);
3712 hi->fakehost = NULL;
3713 }
3714 }
3715 else if (!check_vhost(argv[1], user, cmd)) {
3716 /* check_vhost takes care of error reply */
3717 return 0;
3718 }
3719 else {
3720 if(hi->fakehost)
3721 free(hi->fakehost);
3722 hi->fakehost = strdup(fake);
3723 }
3724 apply_fakehost(hi);
3725 fake = hi->fakehost;
3726 } else
3727 fake = generate_fakehost(hi);
3728
3729 /* Tell them we set the host */
3730 if (!fake)
3731 fake = user_find_message(user, "MSG_NONE");
3732 reply("NSMSG_SET_FAKEHOST", fake);
3733 return 1;
3734 }
3735
3736 static OPTION_FUNC(opt_note)
3737 {
3738 if (!override) {
3739 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3740 return 0;
3741 }
3742
3743 if (argc > 1) {
3744 char *text = unsplit_string(argv + 1, argc - 1, NULL);
3745
3746 if (hi->note)
3747 free(hi->note);
3748
3749 if ((text[0] == '*') && !text[1])
3750 hi->note = NULL;
3751 else {
3752 if (!(hi->note = nickserv_add_note(user->handle_info->handle, now, text)))
3753 hi->note = NULL;
3754 }
3755 }
3756
3757 reply("NSMSG_SET_NOTE", hi->note ? hi->note->note : user_find_message(user, "MSG_NONE"));
3758 return 1;
3759 }
3760
3761 static NICKSERV_FUNC(cmd_reclaim)
3762 {
3763 struct handle_info *hi;
3764 struct nick_info *ni;
3765 struct userNode *victim;
3766
3767 NICKSERV_MIN_PARMS(2);
3768 hi = user->handle_info;
3769 ni = dict_find(nickserv_nick_dict, argv[1], 0);
3770 if (!ni) {
3771 reply("NSMSG_UNKNOWN_NICK", argv[1]);
3772 return 0;
3773 }
3774 if (ni->owner != user->handle_info) {
3775 reply("NSMSG_NOT_YOUR_NICK", ni->nick);
3776 return 0;
3777 }
3778 victim = GetUserH(ni->nick);
3779 if (!victim) {
3780 reply("MSG_NICK_UNKNOWN", ni->nick);
3781 return 0;
3782 }
3783 if (victim == user) {
3784 reply("NSMSG_NICK_USER_YOU");
3785 return 0;
3786 }
3787 nickserv_reclaim(victim, ni, nickserv_conf.reclaim_action);
3788 switch (nickserv_conf.reclaim_action) {
3789 case RECLAIM_NONE: reply("NSMSG_RECLAIMED_NONE"); break;
3790 case RECLAIM_WARN: reply("NSMSG_RECLAIMED_WARN", victim->nick); break;
3791 case RECLAIM_SVSNICK: reply("NSMSG_RECLAIMED_SVSNICK", victim->nick); break;
3792 case RECLAIM_KILL: reply("NSMSG_RECLAIMED_KILL", victim->nick); break;
3793 }
3794 return 1;
3795 }
3796
3797 static NICKSERV_FUNC(cmd_unregnick)
3798 {
3799 const char *nick;
3800 struct handle_info *hi;
3801 struct nick_info *ni;
3802
3803 hi = user->handle_info;
3804 nick = (argc < 2) ? user->nick : (const char*)argv[1];
3805 ni = dict_find(nickserv_nick_dict, nick, NULL);
3806 if (!ni) {
3807 reply("NSMSG_UNKNOWN_NICK", nick);
3808 return 0;
3809 }
3810 if (hi != ni->owner) {
3811 reply("NSMSG_NOT_YOUR_NICK", nick);
3812 return 0;
3813 }
3814 reply("NSMSG_UNREGNICK_SUCCESS", ni->nick);
3815 delete_nick(ni);
3816 return 1;
3817 }
3818
3819 static NICKSERV_FUNC(cmd_ounregnick)
3820 {
3821 struct nick_info *ni;
3822
3823 NICKSERV_MIN_PARMS(2);
3824 if (!(ni = get_nick_info(argv[1]))) {
3825 reply("NSMSG_NICK_NOT_REGISTERED", argv[1]);
3826 return 0;
3827 }
3828 if (!oper_outranks(user, ni->owner))
3829 return 0;
3830 reply("NSMSG_UNREGNICK_SUCCESS", ni->nick);
3831 delete_nick(ni);
3832 return 1;
3833 }
3834
3835 static NICKSERV_FUNC(cmd_unregister)
3836 {
3837 struct handle_info *hi;
3838 char *passwd;
3839
3840 NICKSERV_MIN_PARMS(2);
3841 hi = user->handle_info;
3842 passwd = argv[1];
3843 argv[1] = "****";
3844 if (checkpass(passwd, hi->passwd)) {
3845 if(nickserv_unregister_handle(hi, user, cmd->parent->bot))
3846 return 1;
3847 else
3848 return 0;
3849 } else {
3850 log_module(NS_LOG, LOG_INFO, "Account '%s' tried to unregister with the wrong password.", hi->handle);
3851 reply("NSMSG_PASSWORD_INVALID");
3852 return 0;
3853 }
3854 }
3855
3856 static NICKSERV_FUNC(cmd_ounregister)
3857 {
3858 struct handle_info *hi;
3859 char reason[MAXLEN];
3860 int force;
3861
3862 NICKSERV_MIN_PARMS(2);
3863 if (!(hi = get_victim_oper(user, argv[1])))
3864 return 0;
3865
3866 if (HANDLE_FLAGGED(hi, NODELETE)) {
3867 reply("NSMSG_UNREGISTER_NODELETE", hi->handle);
3868 return 0;
3869 }
3870
3871 force = IsOper(user) && (argc > 2) && !irccasecmp(argv[2], "force");
3872 if (!force &&
3873 ((hi->flags & nickserv_conf.ounregister_flags)
3874 || hi->users
3875 || (hi->last_quit_host[0] && ((unsigned)(now - hi->lastseen) < nickserv_conf.ounregister_inactive)))) {
3876 reply((IsOper(user) ? "NSMSG_UNREGISTER_MUST_FORCE" : "NSMSG_UNREGISTER_CANNOT_FORCE"), hi->handle);
3877 return 0;
3878 }
3879 snprintf(reason, sizeof(reason), "%s unregistered account %s.", user->handle_info->handle, hi->handle);
3880 global_message(MESSAGE_RECIPIENT_STAFF, reason);
3881 if(nickserv_unregister_handle(hi, user, cmd->parent->bot))
3882 return 1;
3883 else
3884 return 0;
3885 }
3886
3887 static NICKSERV_FUNC(cmd_status)
3888 {
3889 if (nickserv_conf.disable_nicks) {
3890 reply("NSMSG_GLOBAL_STATS_NONICK",
3891 dict_size(nickserv_handle_dict));
3892 } else {
3893 if (user->handle_info) {
3894 int cnt=0;
3895 struct nick_info *ni;
3896 for (ni=user->handle_info->nicks; ni; ni=ni->next) cnt++;
3897 reply("NSMSG_HANDLE_STATS", cnt);
3898 } else {
3899 reply("NSMSG_HANDLE_NONE");
3900 }
3901 reply("NSMSG_GLOBAL_STATS",
3902 dict_size(nickserv_handle_dict),
3903 dict_size(nickserv_nick_dict));
3904 }
3905 return 1;
3906 }
3907
3908 static NICKSERV_FUNC(cmd_ghost)
3909 {
3910 struct userNode *target;
3911 char reason[MAXLEN];
3912
3913 NICKSERV_MIN_PARMS(2);
3914 if (!(target = GetUserH(argv[1]))) {
3915 reply("MSG_NICK_UNKNOWN", argv[1]);
3916 return 0;
3917 }
3918 if (target == user) {
3919 reply("NSMSG_CANNOT_GHOST_SELF");
3920 return 0;
3921 }
3922 if (!target->handle_info || (target->handle_info != user->handle_info)) {
3923 reply("NSMSG_CANNOT_GHOST_USER", target->nick);
3924 return 0;
3925 }
3926 snprintf(reason, sizeof(reason), "Ghost kill on account %s (requested by %s).", target->handle_info->handle, user->nick);
3927 DelUser(target, nickserv, 1, reason);
3928 reply("NSMSG_GHOST_KILLED", argv[1]);
3929 return 1;
3930 }
3931
3932 static NICKSERV_FUNC(cmd_vacation)
3933 {
3934 HANDLE_SET_FLAG(user->handle_info, FROZEN);
3935 reply("NSMSG_ON_VACATION");
3936 return 1;
3937 }
3938
3939 static int
3940 nickserv_saxdb_write(struct saxdb_context *ctx) {
3941 dict_iterator_t it;
3942 struct handle_info *hi;
3943 char flags[33];
3944
3945 for (it = dict_first(nickserv_handle_dict); it; it = iter_next(it)) {
3946 hi = iter_data(it);
3947 saxdb_start_record(ctx, iter_key(it), 0);
3948 if (hi->announcements != '?') {
3949 flags[0] = hi->announcements;
3950 flags[1] = 0;
3951 saxdb_write_string(ctx, KEY_ANNOUNCEMENTS, flags);
3952 }
3953 if (hi->cookie) {
3954 struct handle_cookie *cookie = hi->cookie;
3955 char *type;
3956
3957 switch (cookie->type) {
3958 case ACTIVATION: type = KEY_ACTIVATION; break;
3959 case PASSWORD_CHANGE: type = KEY_PASSWORD_CHANGE; break;
3960 case EMAIL_CHANGE: type = KEY_EMAIL_CHANGE; break;
3961 case ALLOWAUTH: type = KEY_ALLOWAUTH; break;
3962 default: type = NULL; break;
3963 }
3964 if (type) {
3965 saxdb_start_record(ctx, KEY_COOKIE, 0);
3966 saxdb_write_string(ctx, KEY_COOKIE_TYPE, type);
3967 saxdb_write_int(ctx, KEY_COOKIE_EXPIRES, cookie->expires);
3968 if (cookie->data)
3969 saxdb_write_string(ctx, KEY_COOKIE_DATA, cookie->data);
3970 saxdb_write_string(ctx, KEY_COOKIE, cookie->cookie);
3971 saxdb_end_record(ctx);
3972 }
3973 }
3974 if (hi->email_addr)
3975 saxdb_write_string(ctx, KEY_EMAIL_ADDR, hi->email_addr);
3976 if (hi->epithet)
3977 saxdb_write_string(ctx, KEY_EPITHET, hi->epithet);
3978 if (hi->note) {
3979 saxdb_start_record(ctx, KEY_NOTE_NOTE, 0);
3980 saxdb_write_string(ctx, KEY_NOTE_SETTER, hi->note->setter);
3981 saxdb_write_int(ctx, KEY_NOTE_DATE, hi->note->date);
3982 saxdb_write_string(ctx, KEY_NOTE_NOTE, hi->note->note);
3983 saxdb_end_record(ctx);
3984 }
3985
3986 if (hi->fakehost)
3987 saxdb_write_string(ctx, KEY_FAKEHOST, hi->fakehost);
3988 if (hi->flags) {
3989 int ii, flen;
3990
3991 for (ii=flen=0; handle_flags[ii]; ++ii)
3992 if (hi->flags & (1 << ii))
3993 flags[flen++] = handle_flags[ii];
3994 flags[flen] = 0;
3995 saxdb_write_string(ctx, KEY_FLAGS, flags);
3996 }
3997 if (hi->infoline)
3998 saxdb_write_string(ctx, KEY_INFO, hi->infoline);
3999 if (hi->last_quit_host[0])
4000 saxdb_write_string(ctx, KEY_LAST_QUIT_HOST, hi->last_quit_host);
4001 saxdb_write_int(ctx, KEY_LAST_SEEN, hi->lastseen);
4002 if (hi->karma != 0)
4003 saxdb_write_sint(ctx, KEY_KARMA, hi->karma);
4004 if (hi->masks->used)
4005 saxdb_write_string_list(ctx, KEY_MASKS, hi->masks);
4006 if (hi->sslfps->used)
4007 saxdb_write_string_list(ctx, KEY_SSLFPS, hi->sslfps);
4008 if (hi->ignores->used)
4009 saxdb_write_string_list(ctx, KEY_IGNORES, hi->ignores);
4010 if (hi->maxlogins)
4011 saxdb_write_int(ctx, KEY_MAXLOGINS, hi->maxlogins);
4012 if (hi->nicks) {
4013 struct string_list *slist;
4014 struct nick_info *ni;
4015
4016 slist = alloc_string_list(nickserv_conf.nicks_per_handle);
4017 for (ni = hi->nicks; ni; ni = ni->next) string_list_append(slist, ni->nick);
4018 saxdb_write_string_list(ctx, KEY_NICKS, slist);
4019 free(slist->list);
4020 free(slist);
4021 }
4022 if (hi->opserv_level)
4023 saxdb_write_int(ctx, KEY_OPSERV_LEVEL, hi->opserv_level);
4024 if (hi->language != lang_C)
4025 saxdb_write_string(ctx, KEY_LANGUAGE, hi->language->name);
4026 saxdb_write_string(ctx, KEY_PASSWD, hi->passwd);
4027 saxdb_write_int(ctx, KEY_REGISTER_ON, hi->registered);
4028 if (hi->screen_width)
4029 saxdb_write_int(ctx, KEY_SCREEN_WIDTH, hi->screen_width);
4030 if (hi->table_width)
4031 saxdb_write_int(ctx, KEY_TABLE_WIDTH, hi->table_width);
4032 flags[0] = hi->userlist_style;
4033 flags[1] = 0;
4034 saxdb_write_string(ctx, KEY_USERLIST_STYLE, flags);
4035 saxdb_end_record(ctx);
4036 }
4037
4038 return 0;
4039 }
4040
4041 static handle_merge_func_t *handle_merge_func_list;
4042 static void **handle_merge_func_list_extra;
4043 static unsigned int handle_merge_func_size = 0, handle_merge_func_used = 0;
4044
4045 void
4046 reg_handle_merge_func(handle_merge_func_t func, void *extra)
4047 {
4048 if (handle_merge_func_used == handle_merge_func_size) {
4049 if (handle_merge_func_size) {
4050 handle_merge_func_size <<= 1;
4051 handle_merge_func_list = realloc(handle_merge_func_list, handle_merge_func_size*sizeof(handle_merge_func_t));
4052 handle_merge_func_list_extra = realloc(handle_merge_func_list_extra, handle_merge_func_size*sizeof(void*));
4053 } else {
4054 handle_merge_func_size = 8;
4055 handle_merge_func_list = malloc(handle_merge_func_size*sizeof(handle_merge_func_t));
4056 handle_merge_func_list_extra = malloc(handle_merge_func_size*sizeof(void*));
4057 }
4058 }
4059 handle_merge_func_list[handle_merge_func_used] = func;
4060 handle_merge_func_list_extra[handle_merge_func_used++] = extra;
4061 }
4062
4063 static NICKSERV_FUNC(cmd_merge)
4064 {
4065 struct handle_info *hi_from, *hi_to;
4066 struct userNode *last_user;
4067 struct userData *cList, *cListNext;
4068 unsigned int ii, jj, n;
4069
4070 NICKSERV_MIN_PARMS(3);
4071
4072 if (!(hi_from = get_victim_oper(user, argv[1])))
4073 return 0;
4074 if (!(hi_to = get_victim_oper(user, argv[2])))
4075 return 0;
4076 if (hi_to == hi_from) {
4077 reply("NSMSG_CANNOT_MERGE_SELF", hi_to->handle);
4078 return 0;
4079 }
4080
4081 for (n=0; n<handle_merge_func_used; n++)
4082 handle_merge_func_list[n](user, hi_to, hi_from, handle_merge_func_list_extra[n]);
4083
4084 /* Append "from" handle's nicks to "to" handle's nick list. */
4085 if (hi_to->nicks) {
4086 struct nick_info *last_ni;
4087 for (last_ni=hi_to->nicks; last_ni->next; last_ni=last_ni->next) ;
4088 last_ni->next = hi_from->nicks;
4089 }
4090 while (hi_from->nicks) {
4091 hi_from->nicks->owner = hi_to;
4092 hi_from->nicks = hi_from->nicks->next;
4093 }
4094
4095 /* Merge the hostmasks. */
4096 for (ii=0; ii<hi_from->masks->used; ii++) {
4097 char *mask = hi_from->masks->list[ii];
4098 for (jj=0; jj<hi_to->masks->used; jj++)
4099 if (match_ircglobs(hi_to->masks->list[jj], mask))
4100 break;
4101 if (jj==hi_to->masks->used) /* Nothing from the "to" handle covered this mask, so add it. */
4102 string_list_append(hi_to->masks, strdup(mask));
4103 }
4104
4105 /* Merge the ignores. */
4106 for (ii=0; ii<hi_from->ignores->used; ii++) {
4107 char *ignore = hi_from->ignores->list[ii];
4108 for (jj=0; jj<hi_to->ignores->used; jj++)
4109 if (match_ircglobs(hi_to->ignores->list[jj], ignore))
4110 break;
4111 if (jj==hi_to->ignores->used) /* Nothing from the "to" handle covered this mask, so add it. */
4112 string_list_append(hi_to->ignores, strdup(ignore));
4113 }
4114
4115 /* Merge the lists of authed users. */
4116 if (hi_to->users) {
4117 for (last_user=hi_to->users; last_user->next_authed; last_user=last_user->next_authed) ;
4118 last_user->next_authed = hi_from->users;
4119 } else {
4120 hi_to->users = hi_from->users;
4121 }
4122 /* Repoint the old "from" handle's users. */
4123 for (last_user=hi_from->users; last_user; last_user=last_user->next_authed) {
4124 last_user->handle_info = hi_to;
4125 }
4126 hi_from->users = NULL;
4127
4128 /* Merge channel userlists. */
4129 for (cList=hi_from->channels; cList; cList=cListNext) {
4130 struct userData *cList2;
4131 cListNext = cList->u_next;
4132 for (cList2=hi_to->channels; cList2; cList2=cList2->u_next)
4133 if (cList->channel == cList2->channel)
4134 break;
4135 if (cList2 && (cList2->access >= cList->access)) {
4136 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);
4137 /* keep cList2 in hi_to; remove cList from hi_from */
4138 del_channel_user(cList, 1);
4139 } else {
4140 if (cList2) {
4141 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);
4142 /* remove the lower-ranking cList2 from hi_to */
4143 del_channel_user(cList2, 1);
4144 } else {
4145 log_module(NS_LOG, LOG_INFO, "Merge: %s had no access in %s", hi_to->handle, cList->channel->channel->name);
4146 }
4147 /* cList needs to be moved from hi_from to hi_to */
4148 cList->handle = hi_to;
4149 /* Remove from linked list for hi_from */
4150 assert(!cList->u_prev);
4151 hi_from->channels = cList->u_next;
4152 if (cList->u_next)
4153 cList->u_next->u_prev = cList->u_prev;
4154 /* Add to linked list for hi_to */
4155 cList->u_prev = NULL;
4156 cList->u_next = hi_to->channels;
4157 if (hi_to->channels)
4158 hi_to->channels->u_prev = cList;
4159 hi_to->channels = cList;
4160 }
4161 }
4162
4163 /* Do they get an OpServ level promotion? */
4164 if (hi_from->opserv_level > hi_to->opserv_level)
4165 hi_to->opserv_level = hi_from->opserv_level;
4166
4167 /* What about last seen time? */
4168 if (hi_from->lastseen > hi_to->lastseen)
4169 hi_to->lastseen = hi_from->lastseen;
4170
4171 /* New karma is the sum of the two original karmas. */
4172 hi_to->karma += hi_from->karma;
4173
4174 /* Does a fakehost carry over? (This intentionally doesn't set it
4175 * for users previously attached to hi_to. They'll just have to
4176 * reconnect.)
4177 */
4178 if (hi_from->fakehost && !hi_to->fakehost)
4179 hi_to->fakehost = strdup(hi_from->fakehost);
4180
4181 /* Notify of success. */
4182 reply("NSMSG_HANDLES_MERGED", hi_from->handle, hi_to->handle);
4183 global_message_args(MESSAGE_RECIPIENT_OPERS, "NSMSG_ACCOUNT_MERGED", user->nick,
4184 user->handle_info->handle, hi_from->handle, hi_to->handle);
4185
4186 /* Unregister the "from" handle. */
4187 nickserv_unregister_handle(hi_from, NULL, cmd->parent->bot);
4188 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
4189 * the process isn't completed.
4190 */
4191
4192 return 1;
4193 }
4194
4195 struct nickserv_discrim {
4196 unsigned long flags_on, flags_off;
4197 time_t min_registered, max_registered;
4198 time_t lastseen;
4199 unsigned int limit;
4200 int min_level, max_level;
4201 int min_karma, max_karma;
4202 enum { SUBSET, EXACT, SUPERSET, LASTQUIT } hostmask_type;
4203 const char *nickmask;
4204 const char *hostmask;
4205 const char *handlemask;
4206 const char *emailmask;
4207 #ifdef WITH_LDAP
4208 unsigned int inldap;
4209 #endif
4210 };
4211
4212 typedef void (*discrim_search_func)(struct userNode *source, struct handle_info *hi);
4213
4214 struct discrim_apply_info {
4215 struct nickserv_discrim *discrim;
4216 discrim_search_func func;
4217 struct userNode *source;
4218 unsigned int matched;
4219 };
4220
4221 static struct nickserv_discrim *
4222 nickserv_discrim_create(struct svccmd *cmd, struct userNode *user, unsigned int argc, char *argv[])
4223 {
4224 unsigned int i;
4225 struct nickserv_discrim *discrim;
4226
4227 discrim = malloc(sizeof(*discrim));
4228 memset(discrim, 0, sizeof(*discrim));
4229 discrim->min_level = 0;
4230 discrim->max_level = INT_MAX;
4231 discrim->limit = 50;
4232 discrim->min_registered = 0;
4233 discrim->max_registered = INT_MAX;
4234 discrim->lastseen = LONG_MAX;
4235 discrim->min_karma = INT_MIN;
4236 discrim->max_karma = INT_MAX;
4237 #ifdef WITH_LDAP
4238 discrim->inldap = 2;
4239 #endif
4240
4241 for (i=0; i<argc; i++) {
4242 if (i == argc - 1) {
4243 reply("MSG_MISSING_PARAMS", argv[i]);
4244 goto fail;
4245 }
4246 if (!irccasecmp(argv[i], "limit")) {
4247 discrim->limit = strtoul(argv[++i], NULL, 0);
4248 } else if (!irccasecmp(argv[i], "flags")) {
4249 nickserv_modify_handle_flags(user, nickserv, argv[++i], &discrim->flags_on, &discrim->flags_off);
4250 } else if (!irccasecmp(argv[i], "registered")) {
4251 const char *cmp = argv[++i];
4252 if (cmp[0] == '<') {
4253 if (cmp[1] == '=') {
4254 discrim->min_registered = now - ParseInterval(cmp+2);
4255 } else {
4256 discrim->min_registered = now - ParseInterval(cmp+1) + 1;
4257 }
4258 } else if (cmp[0] == '=') {
4259 discrim->min_registered = discrim->max_registered = now - ParseInterval(cmp+1);
4260 } else if (cmp[0] == '>') {
4261 if (cmp[1] == '=') {
4262 discrim->max_registered = now - ParseInterval(cmp+2);
4263 } else {
4264 discrim->max_registered = now - ParseInterval(cmp+1) - 1;
4265 }
4266 } else {
4267 reply("MSG_INVALID_CRITERIA", cmp);
4268 }
4269 } else if (!irccasecmp(argv[i], "seen")) {
4270 discrim->lastseen = now - ParseInterval(argv[++i]);
4271 } else if (!nickserv_conf.disable_nicks && !irccasecmp(argv[i], "nickmask")) {
4272 discrim->nickmask = argv[++i];
4273 } else if (!irccasecmp(argv[i], "hostmask")) {
4274 i++;
4275 if (!irccasecmp(argv[i], "exact")) {
4276 if (i == argc - 1) {
4277 reply("MSG_MISSING_PARAMS", argv[i]);
4278 goto fail;
4279 }
4280 discrim->hostmask_type = EXACT;
4281 } else if (!irccasecmp(argv[i], "subset")) {
4282 if (i == argc - 1) {
4283 reply("MSG_MISSING_PARAMS", argv[i]);
4284 goto fail;
4285 }
4286 discrim->hostmask_type = SUBSET;
4287 } else if (!irccasecmp(argv[i], "superset")) {
4288 if (i == argc - 1) {
4289 reply("MSG_MISSING_PARAMS", argv[i]);
4290 goto fail;
4291 }
4292 discrim->hostmask_type = SUPERSET;
4293 } else if (!irccasecmp(argv[i], "lastquit") || !irccasecmp(argv[i], "lastauth")) {
4294 if (i == argc - 1) {
4295 reply("MSG_MISSING_PARAMS", argv[i]);
4296 goto fail;
4297 }
4298 discrim->hostmask_type = LASTQUIT;
4299 } else {
4300 i--;
4301 discrim->hostmask_type = SUPERSET;
4302 }
4303 discrim->hostmask = argv[++i];
4304 } else if (!irccasecmp(argv[i], "handlemask") || !irccasecmp(argv[i], "accountmask") || !irccasecmp(argv[i], "account")) {
4305 if (!irccasecmp(argv[++i], "*")) {
4306 discrim->handlemask = 0;
4307 } else {
4308 discrim->handlemask = argv[i];
4309 }
4310 } else if (!irccasecmp(argv[i], "email")) {
4311 if (user->handle_info->opserv_level < nickserv_conf.email_search_level) {
4312 reply("MSG_NO_SEARCH_ACCESS", "email");
4313 goto fail;
4314 } else if (!irccasecmp(argv[++i], "*")) {
4315 discrim->emailmask = 0;
4316 } else {
4317 discrim->emailmask = argv[i];
4318 }
4319 } else if (!irccasecmp(argv[i], "access")) {
4320 const char *cmp = argv[++i];
4321 if (cmp[0] == '<') {
4322 if (discrim->min_level == 0) discrim->min_level = 1;
4323 if (cmp[1] == '=') {
4324 discrim->max_level = strtoul(cmp+2, NULL, 0);
4325 } else {
4326 discrim->max_level = strtoul(cmp+1, NULL, 0) - 1;
4327 }
4328 } else if (cmp[0] == '=') {
4329 discrim->min_level = discrim->max_level = strtoul(cmp+1, NULL, 0);
4330 } else if (cmp[0] == '>') {
4331 if (cmp[1] == '=') {
4332 discrim->min_level = strtoul(cmp+2, NULL, 0);
4333 } else {
4334 discrim->min_level = strtoul(cmp+1, NULL, 0) + 1;
4335 }
4336 } else {
4337 reply("MSG_INVALID_CRITERIA", cmp);
4338 }
4339 } else if (!irccasecmp(argv[i], "karma")) {
4340 const char *cmp = argv[++i];
4341 if (cmp[0] == '<') {
4342 if (cmp[1] == '=') {
4343 discrim->max_karma = strtoul(cmp+2, NULL, 0);
4344 } else {
4345 discrim->max_karma = strtoul(cmp+1, NULL, 0) - 1;
4346 }
4347 } else if (cmp[0] == '=') {
4348 discrim->min_karma = discrim->max_karma = strtoul(cmp+1, NULL, 0);
4349 } else if (cmp[0] == '>') {
4350 if (cmp[1] == '=') {
4351 discrim->min_karma = strtoul(cmp+2, NULL, 0);
4352 } else {
4353 discrim->min_karma = strtoul(cmp+1, NULL, 0) + 1;
4354 }
4355 } else {
4356 send_message(user, nickserv, "MSG_INVALID_CRITERIA", cmp);
4357 }
4358 #ifdef WITH_LDAP
4359 } else if (nickserv_conf.ldap_enable && !irccasecmp(argv[i], "inldap")) {
4360 i++;
4361 if(true_string(argv[i])) {
4362 discrim->inldap = 1;
4363 }
4364 else if (false_string(argv[i])) {
4365 discrim->inldap = 0;
4366 }
4367 else {
4368 reply("MSG_INVALID_BINARY", argv[i]);
4369 }
4370 #endif
4371 } else {
4372 reply("MSG_INVALID_CRITERIA", argv[i]);
4373 goto fail;
4374 }
4375 }
4376 return discrim;
4377 fail:
4378 free(discrim);
4379 return NULL;
4380 }
4381
4382 static int
4383 nickserv_discrim_match(struct nickserv_discrim *discrim, struct handle_info *hi)
4384 {
4385 if (((discrim->flags_on & hi->flags) != discrim->flags_on)
4386 || (discrim->flags_off & hi->flags)
4387 || (discrim->min_registered > hi->registered)
4388 || (discrim->max_registered < hi->registered)
4389 || (discrim->lastseen < (hi->users?now:hi->lastseen))
4390 || (discrim->handlemask && !match_ircglob(hi->handle, discrim->handlemask))
4391 || (discrim->emailmask && (!hi->email_addr || !match_ircglob(hi->email_addr, discrim->emailmask)))
4392 || (discrim->min_level > hi->opserv_level)
4393 || (discrim->max_level < hi->opserv_level)
4394 || (discrim->min_karma > hi->karma)
4395 || (discrim->max_karma < hi->karma)
4396 ) {
4397 return 0;
4398 }
4399 if (discrim->hostmask) {
4400 unsigned int i;
4401 for (i=0; i<hi->masks->used; i++) {
4402 const char *mask = hi->masks->list[i];
4403 if ((discrim->hostmask_type == SUBSET)
4404 && (match_ircglobs(discrim->hostmask, mask))) break;
4405 else if ((discrim->hostmask_type == EXACT)
4406 && !irccasecmp(discrim->hostmask, mask)) break;
4407 else if ((discrim->hostmask_type == SUPERSET)
4408 && (match_ircglobs(mask, discrim->hostmask))) break;
4409 else if ((discrim->hostmask_type == LASTQUIT)
4410 && (match_ircglobs(discrim->hostmask, hi->last_quit_host))) break;
4411 }
4412 if (i==hi->masks->used) return 0;
4413 }
4414 if (discrim->nickmask) {
4415 struct nick_info *nick = hi->nicks;
4416 while (nick) {
4417 if (match_ircglob(nick->nick, discrim->nickmask)) break;
4418 nick = nick->next;
4419 }
4420 if (!nick) return 0;
4421 }
4422 #ifdef WITH_LDAP
4423 if(nickserv_conf.ldap_enable && discrim->inldap != 2) {
4424 int rc;
4425 rc = ldap_get_user_info(hi->handle, NULL);
4426 if(discrim->inldap == 1 && rc != LDAP_SUCCESS)
4427 return 0;
4428 if(discrim->inldap == 0 && rc == LDAP_SUCCESS)
4429 return 0;
4430 }
4431
4432 #endif
4433 return 1;
4434 }
4435
4436 static unsigned int
4437 nickserv_discrim_search(struct nickserv_discrim *discrim, discrim_search_func dsf, struct userNode *source)
4438 {
4439 dict_iterator_t it, next;
4440 unsigned int matched;
4441
4442 for (it = dict_first(nickserv_handle_dict), matched = 0;
4443 it && (matched < discrim->limit);
4444 it = next) {
4445 next = iter_next(it);
4446 if (nickserv_discrim_match(discrim, iter_data(it))) {
4447 dsf(source, iter_data(it));
4448 matched++;
4449 }
4450 }
4451 return matched;
4452 }
4453
4454 static void
4455 search_print_func(struct userNode *source, struct handle_info *match)
4456 {
4457 send_message(source, nickserv, "NSMSG_SEARCH_MATCH", match->handle);
4458 }
4459
4460 static void
4461 search_count_func(UNUSED_ARG(struct userNode *source), UNUSED_ARG(struct handle_info *match))
4462 {
4463 }
4464
4465 static void
4466 search_unregister_func (struct userNode *source, struct handle_info *match)
4467 {
4468 if (oper_has_access(source, nickserv, match->opserv_level, 0))
4469 nickserv_unregister_handle(match, source, nickserv); // XXX nickserv hard coded
4470 }
4471
4472 #ifdef WITH_LDAP
4473 static void
4474 search_add2ldap_func (struct userNode *source, struct handle_info *match)
4475 {
4476 int rc;
4477 if(match->email_addr && match->passwd && match->handle) {
4478 rc = ldap_do_add(match->handle, match->passwd, match->email_addr);
4479 if(rc != LDAP_SUCCESS) {
4480 send_message(source, nickserv, "NSMSG_LDAP_FAIL_ADD", match->handle, ldap_err2string(rc));
4481 }
4482 }
4483 }
4484 #endif
4485
4486 static int
4487 nickserv_sort_accounts_by_access(const void *a, const void *b)
4488 {
4489 const struct handle_info *hi_a = *(const struct handle_info**)a;
4490 const struct handle_info *hi_b = *(const struct handle_info**)b;
4491 if (hi_a->opserv_level != hi_b->opserv_level)
4492 return hi_b->opserv_level - hi_a->opserv_level;
4493 return irccasecmp(hi_a->handle, hi_b->handle);
4494 }
4495
4496 void
4497 nickserv_show_oper_accounts(struct userNode *user, struct svccmd *cmd)
4498 {
4499 struct handle_info_list hil;
4500 struct helpfile_table tbl;
4501 unsigned int ii;
4502 dict_iterator_t it;
4503 const char **ary;
4504
4505 memset(&hil, 0, sizeof(hil));
4506 for (it = dict_first(nickserv_handle_dict); it; it = iter_next(it)) {
4507 struct handle_info *hi = iter_data(it);
4508 if (hi->opserv_level)
4509 handle_info_list_append(&hil, hi);
4510 }
4511 qsort(hil.list, hil.used, sizeof(hil.list[0]), nickserv_sort_accounts_by_access);
4512 tbl.length = hil.used + 1;
4513 tbl.width = 2;
4514 tbl.flags = TABLE_NO_FREE | TABLE_REPEAT_ROWS | TABLE_REPEAT_HEADERS;
4515 tbl.contents = malloc(tbl.length * sizeof(tbl.contents[0]));
4516 tbl.contents[0] = ary = malloc(tbl.width * sizeof(ary[0]));
4517 ary[0] = "Account";
4518 ary[1] = "Level";
4519 for (ii = 0; ii < hil.used; ) {
4520 ary = malloc(tbl.width * sizeof(ary[0]));
4521 ary[0] = hil.list[ii]->handle;
4522 ary[1] = strtab(hil.list[ii]->opserv_level);
4523 tbl.contents[++ii] = ary;
4524 }
4525 table_send(cmd->parent->bot, user->nick, 0, NULL, tbl);
4526 /*reply("MSG_MATCH_COUNT", hil.used); */
4527 for (ii = 0; ii < hil.used; ii++)
4528 free(tbl.contents[ii]);
4529 free(tbl.contents);
4530 free(hil.list);
4531 }
4532
4533 static NICKSERV_FUNC(cmd_search)
4534 {
4535 struct nickserv_discrim *discrim;
4536 discrim_search_func action;
4537 struct svccmd *subcmd;
4538 unsigned int matches;
4539 char buf[MAXLEN];
4540
4541 NICKSERV_MIN_PARMS(3);
4542 sprintf(buf, "search %s", argv[1]);
4543 subcmd = dict_find(nickserv_service->commands, buf, NULL);
4544 if (!irccasecmp(argv[1], "print"))
4545 action = search_print_func;
4546 else if (!irccasecmp(argv[1], "count"))
4547 action = search_count_func;
4548 else if (!irccasecmp(argv[1], "unregister"))
4549 action = search_unregister_func;
4550 #ifdef WITH_LDAP
4551 else if (nickserv_conf.ldap_enable && !irccasecmp(argv[1], "add2ldap"))
4552 action = search_add2ldap_func;
4553 #endif
4554 else {
4555 reply("NSMSG_INVALID_ACTION", argv[1]);
4556 return 0;
4557 }
4558
4559 if (subcmd && !svccmd_can_invoke(user, nickserv, subcmd, NULL, SVCCMD_NOISY))
4560 return 0;
4561
4562 discrim = nickserv_discrim_create(cmd, user, argc-2, argv+2);
4563 if (!discrim)
4564 return 0;
4565
4566 if (action == search_print_func)
4567 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4568 else if (action == search_count_func)
4569 discrim->limit = INT_MAX;
4570
4571 matches = nickserv_discrim_search(discrim, action, user);
4572
4573 if (matches)
4574 reply("MSG_MATCH_COUNT", matches);
4575 else
4576 reply("MSG_NO_MATCHES");
4577
4578 free(discrim);
4579 return 0;
4580 }
4581
4582 static MODCMD_FUNC(cmd_checkpass)
4583 {
4584 struct handle_info *hi;
4585
4586 NICKSERV_MIN_PARMS(3);
4587 if (!(hi = get_handle_info(argv[1]))) {
4588 reply("MSG_HANDLE_UNKNOWN", argv[1]);
4589 return 0;
4590 }
4591 if (checkpass(argv[2], hi->passwd))
4592 reply("CHECKPASS_YES");
4593 else
4594 reply("CHECKPASS_NO");
4595 argv[2] = "****";
4596 return 1;
4597 }
4598
4599 static MODCMD_FUNC(cmd_checkemail)
4600 {
4601 struct handle_info *hi;
4602
4603 NICKSERV_MIN_PARMS(3);
4604 if (!(hi = modcmd_get_handle_info(user, argv[1]))) {
4605 return 0;
4606 }
4607 if (!hi->email_addr)
4608 reply("CHECKEMAIL_NOT_SET");
4609 else if (!irccasecmp(argv[2], hi->email_addr))
4610 reply("CHECKEMAIL_YES");
4611 else
4612 reply("CHECKEMAIL_NO");
4613 return 1;
4614 }
4615
4616 static void
4617 nickserv_db_read_handle(char *handle, dict_t obj)
4618 {
4619 const char *str;
4620 struct string_list *masks, *sslfps, *slist, *ignores;
4621 struct handle_info *hi;
4622 struct userNode *authed_users;
4623 struct userData *channel_list;
4624 unsigned long int id;
4625 unsigned int ii;
4626 dict_t subdb;
4627 char *setter, *note;
4628 time_t date;
4629
4630 str = database_get_data(obj, KEY_ID, RECDB_QSTRING);
4631 id = str ? strtoul(str, NULL, 0) : 0;
4632 str = database_get_data(obj, KEY_PASSWD, RECDB_QSTRING);
4633 if (!str) {
4634 log_module(NS_LOG, LOG_WARNING, "did not find a password for %s -- skipping user.", handle);
4635 return;
4636 }
4637 if ((hi = get_handle_info(handle))) {
4638 authed_users = hi->users;
4639 channel_list = hi->channels;
4640 hi->users = NULL;
4641 hi->channels = NULL;
4642 dict_remove(nickserv_handle_dict, hi->handle);
4643 } else {
4644 authed_users = NULL;
4645 channel_list = NULL;
4646 }
4647 if(nickserv_conf.force_handles_lowercase)
4648 irc_strtolower(handle);
4649 hi = register_handle(handle, str, id);
4650 if (authed_users) {
4651 hi->users = authed_users;
4652 while (authed_users) {
4653 authed_users->handle_info = hi;
4654 authed_users = authed_users->next_authed;
4655 }
4656 }
4657 hi->channels = channel_list;
4658 masks = database_get_data(obj, KEY_MASKS, RECDB_STRING_LIST);
4659 hi->masks = masks ? string_list_copy(masks) : alloc_string_list(1);
4660 sslfps = database_get_data(obj, KEY_SSLFPS, RECDB_STRING_LIST);
4661 hi->sslfps = sslfps ? string_list_copy(sslfps) : alloc_string_list(1);
4662 ignores = database_get_data(obj, KEY_IGNORES, RECDB_STRING_LIST);
4663 hi->ignores = ignores ? string_list_copy(ignores) : alloc_string_list(1);
4664 str = database_get_data(obj, KEY_MAXLOGINS, RECDB_QSTRING);
4665 hi->maxlogins = str ? strtoul(str, NULL, 0) : 0;
4666 str = database_get_data(obj, KEY_LANGUAGE, RECDB_QSTRING);
4667 hi->language = language_find(str ? str : "C");
4668 str = database_get_data(obj, KEY_OPSERV_LEVEL, RECDB_QSTRING);
4669 hi->opserv_level = str ? strtoul(str, NULL, 0) : 0;
4670 str = database_get_data(obj, KEY_INFO, RECDB_QSTRING);
4671 if (str)
4672 hi->infoline = strdup(str);
4673 str = database_get_data(obj, KEY_REGISTER_ON, RECDB_QSTRING);
4674 hi->registered = str ? (time_t)strtoul(str, NULL, 0) : now;
4675 str = database_get_data(obj, KEY_LAST_SEEN, RECDB_QSTRING);
4676 hi->lastseen = str ? (time_t)strtoul(str, NULL, 0) : hi->registered;
4677 str = database_get_data(obj, KEY_KARMA, RECDB_QSTRING);
4678 hi->karma = str ? strtoul(str, NULL, 0) : 0;
4679 /* We want to read the nicks even if disable_nicks is set. This is so
4680 * that we don't lose the nick data entirely. */
4681 slist = database_get_data(obj, KEY_NICKS, RECDB_STRING_LIST);
4682 if (slist) {
4683 for (ii=0; ii<slist->used; ii++)
4684 register_nick(slist->list[ii], hi);
4685 }
4686 str = database_get_data(obj, KEY_FLAGS, RECDB_QSTRING);
4687 if (str) {
4688 for (ii=0; str[ii]; ii++)
4689 hi->flags |= 1 << (handle_inverse_flags[(unsigned char)str[ii]] - 1);
4690 }
4691 str = database_get_data(obj, KEY_USERLIST_STYLE, RECDB_QSTRING);
4692 hi->userlist_style = str ? str[0] : HI_DEFAULT_STYLE;
4693 str = database_get_data(obj, KEY_ANNOUNCEMENTS, RECDB_QSTRING);
4694 hi->announcements = str ? str[0] : '?';
4695 str = database_get_data(obj, KEY_SCREEN_WIDTH, RECDB_QSTRING);
4696 hi->screen_width = str ? strtoul(str, NULL, 0) : 0;
4697 str = database_get_data(obj, KEY_TABLE_WIDTH, RECDB_QSTRING);
4698 hi->table_width = str ? strtoul(str, NULL, 0) : 0;
4699 str = database_get_data(obj, KEY_LAST_QUIT_HOST, RECDB_QSTRING);
4700 if (!str)
4701 str = database_get_data(obj, KEY_LAST_AUTHED_HOST, RECDB_QSTRING);
4702 if (str)
4703 safestrncpy(hi->last_quit_host, str, sizeof(hi->last_quit_host));
4704 str = database_get_data(obj, KEY_EMAIL_ADDR, RECDB_QSTRING);
4705 if (str)
4706 nickserv_set_email_addr(hi, str);
4707 str = database_get_data(obj, KEY_EPITHET, RECDB_QSTRING);
4708 if (str)
4709 hi->epithet = strdup(str);
4710 subdb = database_get_data(obj, KEY_NOTE_NOTE, RECDB_OBJECT);
4711 if (subdb) {
4712 setter = database_get_data(subdb, KEY_NOTE_SETTER, RECDB_QSTRING);
4713 str = database_get_data(subdb, KEY_NOTE_DATE, RECDB_QSTRING);
4714 date = str ? (time_t)strtoul(str, NULL, 0) : now;
4715 note = database_get_data(subdb, KEY_NOTE_NOTE, RECDB_QSTRING);
4716 if (setter && date && note)
4717 {
4718 if (!(hi->note = nickserv_add_note(setter, date, note)))
4719 hi->note = NULL;
4720 }
4721 }
4722
4723 str = database_get_data(obj, KEY_FAKEHOST, RECDB_QSTRING);
4724 if (str)
4725 hi->fakehost = strdup(str);
4726
4727 subdb = database_get_data(obj, KEY_COOKIE, RECDB_OBJECT);
4728 if (subdb) {
4729 const char *data, *type, *expires, *cookie_str;
4730 struct handle_cookie *cookie;
4731
4732 cookie = calloc(1, sizeof(*cookie));
4733 type = database_get_data(subdb, KEY_COOKIE_TYPE, RECDB_QSTRING);
4734 data = database_get_data(subdb, KEY_COOKIE_DATA, RECDB_QSTRING);
4735 expires = database_get_data(subdb, KEY_COOKIE_EXPIRES, RECDB_QSTRING);
4736 cookie_str = database_get_data(subdb, KEY_COOKIE, RECDB_QSTRING);
4737 if (!type || !expires || !cookie_str) {
4738 log_module(NS_LOG, LOG_ERROR, "Missing field(s) from cookie for account %s; dropping cookie.", hi->handle);
4739 goto cookie_out;
4740 }
4741 if (!irccasecmp(type, KEY_ACTIVATION))
4742 cookie->type = ACTIVATION;
4743 else if (!irccasecmp(type, KEY_PASSWORD_CHANGE))
4744 cookie->type = PASSWORD_CHANGE;
4745 else if (!irccasecmp(type, KEY_EMAIL_CHANGE))
4746 cookie->type = EMAIL_CHANGE;
4747 else if (!irccasecmp(type, KEY_ALLOWAUTH))
4748 cookie->type = ALLOWAUTH;
4749 else {
4750 log_module(NS_LOG, LOG_ERROR, "Invalid cookie type %s for account %s; dropping cookie.", type, handle);
4751 goto cookie_out;
4752 }
4753 cookie->expires = strtoul(expires, NULL, 0);
4754 if (cookie->expires < now)
4755 goto cookie_out;
4756 if (data)
4757 cookie->data = strdup(data);
4758 safestrncpy(cookie->cookie, cookie_str, sizeof(cookie->cookie));
4759 cookie->hi = hi;
4760 cookie_out:
4761 if (cookie->hi)
4762 nickserv_bake_cookie(cookie);
4763 else
4764 nickserv_free_cookie(cookie);
4765 }
4766 }
4767
4768 static int
4769 nickserv_saxdb_read(dict_t db) {
4770 dict_iterator_t it;
4771 struct record_data *rd;
4772 char *handle;
4773
4774 for (it=dict_first(db); it; it=iter_next(it)) {
4775 rd = iter_data(it);
4776 handle = strdup(iter_key(it));
4777 nickserv_db_read_handle(handle, rd->d.object);
4778 free(handle);
4779 }
4780 return 0;
4781 }
4782
4783 static NICKSERV_FUNC(cmd_mergedb)
4784 {
4785 struct timeval start, stop;
4786 dict_t db;
4787
4788 NICKSERV_MIN_PARMS(2);
4789 gettimeofday(&start, NULL);
4790 if (!(db = parse_database(argv[1]))) {
4791 reply("NSMSG_DB_UNREADABLE", argv[1]);
4792 return 0;
4793 }
4794 nickserv_saxdb_read(db);
4795 free_database(db);
4796 gettimeofday(&stop, NULL);
4797 stop.tv_sec -= start.tv_sec;
4798 stop.tv_usec -= start.tv_usec;
4799 if (stop.tv_usec < 0) {
4800 stop.tv_sec -= 1;
4801 stop.tv_usec += 1000000;
4802 }
4803 reply("NSMSG_DB_MERGED", argv[1], stop.tv_sec, stop.tv_usec/1000);
4804 return 1;
4805 }
4806
4807 static void
4808 expire_handles(UNUSED_ARG(void *data))
4809 {
4810 dict_iterator_t it, next;
4811 time_t expiry;
4812 struct handle_info *hi;
4813
4814 for (it=dict_first(nickserv_handle_dict); it; it=next) {
4815 next = iter_next(it);
4816 hi = iter_data(it);
4817 if ((hi->opserv_level > 0)
4818 || hi->users
4819 || HANDLE_FLAGGED(hi, FROZEN)
4820 || HANDLE_FLAGGED(hi, NODELETE)) {
4821 continue;
4822 }
4823 expiry = hi->channels ? nickserv_conf.handle_expire_delay : nickserv_conf.nochan_handle_expire_delay;
4824 if ((now - hi->lastseen) > expiry) {
4825 log_module(NS_LOG, LOG_INFO, "Expiring account %s for inactivity.", hi->handle);
4826 nickserv_unregister_handle(hi, NULL, NULL);
4827 }
4828 }
4829
4830 if (nickserv_conf.handle_expire_frequency)
4831 timeq_add(now + nickserv_conf.handle_expire_frequency, expire_handles, NULL);
4832 }
4833
4834 static void
4835 nickserv_load_dict(const char *fname)
4836 {
4837 FILE *file;
4838 char line[128];
4839 if (!(file = fopen(fname, "r"))) {
4840 log_module(NS_LOG, LOG_ERROR, "Unable to open dictionary file %s: %s", fname, strerror(errno));
4841 return;
4842 }
4843 while (fgets(line, sizeof(line), file)) {
4844 if (!line[0])
4845 continue;
4846 if (line[strlen(line)-1] == '\n')
4847 line[strlen(line)-1] = 0;
4848 dict_insert(nickserv_conf.weak_password_dict, strdup(line), NULL);
4849 }
4850 fclose(file);
4851 log_module(NS_LOG, LOG_INFO, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf.weak_password_dict));
4852 }
4853
4854 static enum reclaim_action
4855 reclaim_action_from_string(const char *str) {
4856 if (!str)
4857 return RECLAIM_NONE;
4858 else if (!irccasecmp(str, "warn"))
4859 return RECLAIM_WARN;
4860 else if (!irccasecmp(str, "svsnick"))
4861 return RECLAIM_SVSNICK;
4862 else if (!irccasecmp(str, "kill"))
4863 return RECLAIM_KILL;
4864 else
4865 return RECLAIM_NONE;
4866 }
4867
4868 static void
4869 nickserv_conf_read(void)
4870 {
4871 dict_t conf_node, child;
4872 const char *str;
4873 dict_iterator_t it;
4874 struct string_list *strlist;
4875
4876 if (!(conf_node = conf_get_data(NICKSERV_CONF_NAME, RECDB_OBJECT))) {
4877 log_module(NS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME);
4878 return;
4879 }
4880 str = database_get_data(conf_node, KEY_VALID_HANDLE_REGEX, RECDB_QSTRING);
4881 if (!str)
4882 str = database_get_data(conf_node, KEY_VALID_ACCOUNT_REGEX, RECDB_QSTRING);
4883 if (nickserv_conf.valid_handle_regex_set)
4884 regfree(&nickserv_conf.valid_handle_regex);
4885 if (str) {
4886 int err = regcomp(&nickserv_conf.valid_handle_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
4887 nickserv_conf.valid_handle_regex_set = !err;
4888 if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_account_regex (error %d)", err);
4889 } else {
4890 nickserv_conf.valid_handle_regex_set = 0;
4891 }
4892 str = database_get_data(conf_node, KEY_VALID_NICK_REGEX, RECDB_QSTRING);
4893 if (nickserv_conf.valid_nick_regex_set)
4894 regfree(&nickserv_conf.valid_nick_regex);
4895 if (str) {
4896 int err = regcomp(&nickserv_conf.valid_nick_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
4897 nickserv_conf.valid_nick_regex_set = !err;
4898 if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_nick_regex (error %d)", err);
4899 } else {
4900 nickserv_conf.valid_nick_regex_set = 0;
4901 }
4902 str = database_get_data(conf_node, KEY_VALID_FAKEHOST_REGEX, RECDB_QSTRING);
4903 if (nickserv_conf.valid_fakehost_regex_set)
4904 regfree(&nickserv_conf.valid_fakehost_regex);
4905 if (str) {
4906 int err = regcomp(&nickserv_conf.valid_fakehost_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
4907 nickserv_conf.valid_fakehost_regex_set = !err;
4908 if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_fakehost_regex (error %d)", err);
4909 } else {
4910 nickserv_conf.valid_fakehost_regex_set = 0;
4911 }
4912 str = database_get_data(conf_node, KEY_NICKS_PER_HANDLE, RECDB_QSTRING);
4913 if (!str)
4914 str = database_get_data(conf_node, KEY_NICKS_PER_ACCOUNT, RECDB_QSTRING);
4915 nickserv_conf.nicks_per_handle = str ? strtoul(str, NULL, 0) : 4;
4916 str = database_get_data(conf_node, KEY_DISABLE_NICKS, RECDB_QSTRING);
4917 nickserv_conf.disable_nicks = str ? strtoul(str, NULL, 0) : 0;
4918 str = database_get_data(conf_node, KEY_DEFAULT_HOSTMASK, RECDB_QSTRING);
4919 nickserv_conf.default_hostmask = str ? !disabled_string(str) : 0;
4920 str = database_get_data(conf_node, KEY_PASSWORD_MIN_LENGTH, RECDB_QSTRING);
4921 nickserv_conf.password_min_length = str ? strtoul(str, NULL, 0) : 0;
4922 str = database_get_data(conf_node, KEY_PASSWORD_MIN_DIGITS, RECDB_QSTRING);
4923 nickserv_conf.password_min_digits = str ? strtoul(str, NULL, 0) : 0;
4924 str = database_get_data(conf_node, KEY_PASSWORD_MIN_UPPER, RECDB_QSTRING);
4925 nickserv_conf.password_min_upper = str ? strtoul(str, NULL, 0) : 0;
4926 str = database_get_data(conf_node, KEY_PASSWORD_MIN_LOWER, RECDB_QSTRING);
4927 nickserv_conf.password_min_lower = str ? strtoul(str, NULL, 0) : 0;
4928 str = database_get_data(conf_node, KEY_DB_BACKUP_FREQ, RECDB_QSTRING);
4929 nickserv_conf.db_backup_frequency = str ? ParseInterval(str) : 7200;
4930 str = database_get_data(conf_node, KEY_MODOPER_LEVEL, RECDB_QSTRING);
4931 nickserv_conf.modoper_level = str ? strtoul(str, NULL, 0) : 900;
4932 str = database_get_data(conf_node, KEY_SET_EPITHET_LEVEL, RECDB_QSTRING);
4933 nickserv_conf.set_epithet_level = str ? strtoul(str, NULL, 0) : 1;
4934 str = database_get_data(conf_node, KEY_SET_TITLE_LEVEL, RECDB_QSTRING);
4935 nickserv_conf.set_title_level = str ? strtoul(str, NULL, 0) : 900;
4936 str = database_get_data(conf_node, KEY_SET_FAKEHOST_LEVEL, RECDB_QSTRING);
4937 nickserv_conf.set_fakehost_level = str ? strtoul(str, NULL, 0) : 1000;
4938 str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_FREQ, RECDB_QSTRING);
4939 if (!str)
4940 str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_FREQ, RECDB_QSTRING);
4941 nickserv_conf.handle_expire_frequency = str ? ParseInterval(str) : 86400;
4942 str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_DELAY, RECDB_QSTRING);
4943 if (!str)
4944 str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
4945 nickserv_conf.handle_expire_delay = str ? ParseInterval(str) : 86400*30;
4946 str = database_get_data(conf_node, KEY_NOCHAN_HANDLE_EXPIRE_DELAY, RECDB_QSTRING);
4947 if (!str)
4948 str = database_get_data(conf_node, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
4949 nickserv_conf.nochan_handle_expire_delay = str ? ParseInterval(str) : 86400*15;
4950 str = database_get_data(conf_node, "warn_clone_auth", RECDB_QSTRING);
4951 nickserv_conf.warn_clone_auth = str ? !disabled_string(str) : 1;
4952 str = database_get_data(conf_node, "default_maxlogins", RECDB_QSTRING);
4953 nickserv_conf.default_maxlogins = str ? strtoul(str, NULL, 0) : 2;
4954 str = database_get_data(conf_node, "hard_maxlogins", RECDB_QSTRING);
4955 str = database_get_data(conf_node, KEY_OUNREGISTER_INACTIVE, RECDB_QSTRING);
4956 nickserv_conf.ounregister_inactive = str ? ParseInterval(str) : 86400*28;
4957 str = database_get_data(conf_node, KEY_OUNREGISTER_FLAGS, RECDB_QSTRING);
4958 if (!str)
4959 str = "ShgsfnHbu";
4960 nickserv_conf.ounregister_flags = 0;
4961 while(*str) {
4962 unsigned int pos = handle_inverse_flags[(unsigned char)*str];
4963 str++;
4964 if(pos)
4965 nickserv_conf.ounregister_flags |= 1 << (pos - 1);
4966 }
4967 nickserv_conf.hard_maxlogins = str ? strtoul(str, NULL, 0) : 10;
4968 if (!nickserv_conf.disable_nicks) {
4969 str = database_get_data(conf_node, "reclaim_action", RECDB_QSTRING);
4970 nickserv_conf.reclaim_action = str ? reclaim_action_from_string(str) : RECLAIM_NONE;
4971 str = database_get_data(conf_node, "warn_nick_owned", RECDB_QSTRING);
4972 nickserv_conf.warn_nick_owned = str ? enabled_string(str) : 0;
4973 str = database_get_data(conf_node, "auto_reclaim_action", RECDB_QSTRING);
4974 nickserv_conf.auto_reclaim_action = str ? reclaim_action_from_string(str) : RECLAIM_NONE;
4975 str = database_get_data(conf_node, "auto_reclaim_delay", RECDB_QSTRING);
4976 nickserv_conf.auto_reclaim_delay = str ? ParseInterval(str) : 0;
4977 }
4978 child = database_get_data(conf_node, KEY_FLAG_LEVELS, RECDB_OBJECT);
4979 for (it=dict_first(child); it; it=iter_next(it)) {
4980 const char *key = iter_key(it), *value;
4981 unsigned char flag;
4982 int pos;
4983
4984 if (!strncasecmp(key, "uc_", 3))
4985 flag = toupper(key[3]);
4986 else if (!strncasecmp(key, "lc_", 3))
4987 flag = tolower(key[3]);
4988 else
4989 flag = key[0];
4990
4991 if ((pos = handle_inverse_flags[flag])) {
4992 value = GET_RECORD_QSTRING((struct record_data*)iter_data(it));
4993 flag_access_levels[pos - 1] = strtoul(value, NULL, 0);
4994 }
4995 }
4996 if (nickserv_conf.weak_password_dict)
4997 dict_delete(nickserv_conf.weak_password_dict);
4998 nickserv_conf.weak_password_dict = dict_new();
4999 dict_set_free_keys(nickserv_conf.weak_password_dict, free);
5000 dict_insert(nickserv_conf.weak_password_dict, strdup("password"), NULL);
5001 dict_insert(nickserv_conf.weak_password_dict, strdup("<password>"), NULL);
5002 str = database_get_data(conf_node, KEY_DICT_FILE, RECDB_QSTRING);
5003 if (str)
5004 nickserv_load_dict(str);
5005 str = database_get_data(conf_node, KEY_NICK, RECDB_QSTRING);
5006 if (nickserv && str)
5007 NickChange(nickserv, str, 0);
5008 str = database_get_data(conf_node, KEY_AUTOGAG_ENABLED, RECDB_QSTRING);
5009 nickserv_conf.autogag_enabled = str ? strtoul(str, NULL, 0) : 1;
5010 str = database_get_data(conf_node, KEY_AUTOGAG_DURATION, RECDB_QSTRING);
5011 nickserv_conf.autogag_duration = str ? ParseInterval(str) : 1800;
5012 str = database_get_data(conf_node, KEY_EMAIL_VISIBLE_LEVEL, RECDB_QSTRING);
5013 nickserv_conf.email_visible_level = str ? strtoul(str, NULL, 0) : 800;
5014 str = database_get_data(conf_node, KEY_EMAIL_ENABLED, RECDB_QSTRING);
5015 nickserv_conf.email_enabled = str ? enabled_string(str) : 0;
5016 str = database_get_data(conf_node, KEY_SYNC_LOG, RECDB_QSTRING);
5017 nickserv_conf.sync_log = str ? enabled_string(str) : 0;
5018 str = database_get_data(conf_node, KEY_COOKIE_TIMEOUT, RECDB_QSTRING);
5019 nickserv_conf.cookie_timeout = str ? ParseInterval(str) : 24*3600;
5020 str = database_get_data(conf_node, KEY_EMAIL_REQUIRED, RECDB_QSTRING);
5021 nickserv_conf.email_required = (nickserv_conf.email_enabled && str) ? enabled_string(str) : 0;
5022 str = database_get_data(conf_node, KEY_ACCOUNTS_PER_EMAIL, RECDB_QSTRING);
5023 nickserv_conf.handles_per_email = str ? strtoul(str, NULL, 0) : 1;
5024 str = database_get_data(conf_node, KEY_EMAIL_SEARCH_LEVEL, RECDB_QSTRING);
5025 nickserv_conf.email_search_level = str ? strtoul(str, NULL, 0) : 600;
5026 str = database_get_data(conf_node, KEY_TITLEHOST_SUFFIX, RECDB_QSTRING);
5027 nickserv_conf.titlehost_suffix = str ? str : "example.net";
5028
5029 free_string_list(nickserv_conf.denied_fakehost_words);
5030 strlist = database_get_data(conf_node, KEY_DENIED_FAKEHOST_WORDS, RECDB_STRING_LIST);
5031 if(strlist)
5032 strlist = string_list_copy(strlist);
5033 else {
5034 strlist = alloc_string_list(4);
5035 string_list_append(strlist, strdup("sex"));
5036 string_list_append(strlist, strdup("fuck"));
5037 }
5038 nickserv_conf.denied_fakehost_words = strlist;
5039
5040 str = database_get_data(conf_node, KEY_DEFAULT_STYLE, RECDB_QSTRING);
5041 nickserv_conf.default_style = str ? str[0] : HI_DEFAULT_STYLE;
5042
5043 str = database_get_data(conf_node, KEY_AUTO_OPER, RECDB_QSTRING);
5044 nickserv_conf.auto_oper = str ? str : "";
5045
5046 str = database_get_data(conf_node, KEY_AUTO_ADMIN, RECDB_QSTRING);
5047 nickserv_conf.auto_admin = str ? str : "";
5048
5049 str = database_get_data(conf_node, KEY_AUTO_OPER_PRIVS, RECDB_QSTRING);
5050 nickserv_conf.auto_oper_privs = str ? str : "";
5051
5052 str = database_get_data(conf_node, KEY_AUTO_ADMIN_PRIVS, RECDB_QSTRING);
5053 nickserv_conf.auto_admin_privs = str ? str : "";
5054
5055 str = conf_get_data("server/network", RECDB_QSTRING);
5056 nickserv_conf.network_name = str ? str : "some IRC network";
5057 if (!nickserv_conf.auth_policer_params) {
5058 nickserv_conf.auth_policer_params = policer_params_new();
5059 policer_params_set(nickserv_conf.auth_policer_params, "size", "5");
5060 policer_params_set(nickserv_conf.auth_policer_params, "drain-rate", "0.05");
5061 }
5062 child = database_get_data(conf_node, KEY_AUTH_POLICER, RECDB_OBJECT);
5063 for (it=dict_first(child); it; it=iter_next(it))
5064 set_policer_param(iter_key(it), iter_data(it), nickserv_conf.auth_policer_params);
5065
5066 str = database_get_data(conf_node, KEY_LDAP_ENABLE, RECDB_QSTRING);
5067 nickserv_conf.ldap_enable = str ? strtoul(str, NULL, 0) : 0;
5068
5069 str = database_get_data(conf_node, KEY_FORCE_HANDLES_LOWERCASE, RECDB_QSTRING);
5070 nickserv_conf.force_handles_lowercase = str ? strtol(str, NULL, 0) : 0;
5071
5072 #ifndef WITH_LDAP
5073 if(nickserv_conf.ldap_enable > 0) {
5074 /* ldap is enabled but not compiled in - error out */
5075 log_module(MAIN_LOG, LOG_ERROR, "ldap is enabled in config, but not compiled in!");
5076 nickserv_conf.ldap_enable = 0;
5077 sleep(5);
5078 }
5079 #endif
5080
5081 #ifdef WITH_LDAP
5082 str = database_get_data(conf_node, KEY_LDAP_URI, RECDB_QSTRING);
5083 nickserv_conf.ldap_uri = str ? str : "";
5084
5085 str = database_get_data(conf_node, KEY_LDAP_BASE, RECDB_QSTRING);
5086 nickserv_conf.ldap_base = str ? str : "";
5087
5088 str = database_get_data(conf_node, KEY_LDAP_DN_FMT, RECDB_QSTRING);
5089 nickserv_conf.ldap_dn_fmt = str ? str : "";
5090
5091 str = database_get_data(conf_node, KEY_LDAP_VERSION, RECDB_QSTRING);
5092 nickserv_conf.ldap_version = str ? strtoul(str, NULL, 0) : 3;
5093
5094 str = database_get_data(conf_node, KEY_LDAP_AUTOCREATE, RECDB_QSTRING);
5095 nickserv_conf.ldap_autocreate = str ? strtoul(str, NULL, 0) : 0;
5096
5097 str = database_get_data(conf_node, KEY_LDAP_TIMEOUT, RECDB_QSTRING);
5098 nickserv_conf.ldap_timeout = str ? strtoul(str, NULL, 0) : 5;
5099
5100 str = database_get_data(conf_node, KEY_LDAP_ADMIN_DN, RECDB_QSTRING);
5101 nickserv_conf.ldap_admin_dn = str ? str : "";
5102
5103 str = database_get_data(conf_node, KEY_LDAP_ADMIN_PASS, RECDB_QSTRING);
5104 nickserv_conf.ldap_admin_pass = str ? str : "";
5105
5106 str = database_get_data(conf_node, KEY_LDAP_FIELD_ACCOUNT, RECDB_QSTRING);
5107 nickserv_conf.ldap_field_account = str ? str : "";
5108
5109 str = database_get_data(conf_node, KEY_LDAP_FIELD_PASSWORD, RECDB_QSTRING);
5110 nickserv_conf.ldap_field_password = str ? str : "";
5111
5112 str = database_get_data(conf_node, KEY_LDAP_FIELD_EMAIL, RECDB_QSTRING);
5113 nickserv_conf.ldap_field_email = str ? str : "";
5114
5115 str = database_get_data(conf_node, KEY_LDAP_FIELD_OSLEVEL, RECDB_QSTRING);
5116 nickserv_conf.ldap_field_oslevel = str ? str : "";
5117
5118 str = database_get_data(conf_node, KEY_LDAP_OPER_GROUP_DN, RECDB_QSTRING);
5119 nickserv_conf.ldap_oper_group_dn = str ? str : "";
5120
5121 str = database_get_data(conf_node, KEY_LDAP_OPER_GROUP_LEVEL, RECDB_QSTRING);
5122 nickserv_conf.ldap_oper_group_level = str ? strtoul(str, NULL, 0) : 99;
5123
5124 str = database_get_data(conf_node, KEY_LDAP_FIELD_GROUP_MEMBER, RECDB_QSTRING);
5125 nickserv_conf.ldap_field_group_member = str ? str : "";
5126
5127 free_string_list(nickserv_conf.ldap_object_classes);
5128 strlist = database_get_data(conf_node, KEY_LDAP_OBJECT_CLASSES, RECDB_STRING_LIST);
5129 if(strlist)
5130 strlist = string_list_copy(strlist);
5131 else {
5132 strlist = alloc_string_list(4);
5133 string_list_append(strlist, strdup("top"));
5134 }
5135 nickserv_conf.ldap_object_classes = strlist;
5136
5137 #endif
5138
5139 }
5140
5141 static void
5142 nickserv_reclaim(struct userNode *user, struct nick_info *ni, enum reclaim_action action) {
5143 const char *msg;
5144 char newnick[NICKLEN+1];
5145
5146 assert(user);
5147 assert(ni);
5148 switch (action) {
5149 case RECLAIM_NONE:
5150 /* do nothing */
5151 break;
5152 case RECLAIM_WARN:
5153 send_message(user, nickserv, "NSMSG_RECLAIM_WARN", ni->nick, ni->owner->handle);
5154 send_message(user, nickserv, "NSMSG_RECLAIM_HOWTO", ni->owner->handle, nickserv->nick, self->name, ni->owner->handle);
5155 break;
5156 case RECLAIM_SVSNICK:
5157 do {
5158 snprintf(newnick, sizeof(newnick), "Guest%d", rand()%10000);
5159 } while (GetUserH(newnick));
5160 irc_svsnick(nickserv, user, newnick);
5161 break;
5162 case RECLAIM_KILL:
5163 msg = user_find_message(user, "NSMSG_RECLAIM_KILL");
5164 DelUser(user, nickserv, 1, msg);
5165 break;
5166 }
5167 }
5168
5169 static void
5170 nickserv_reclaim_p(void *data) {
5171 struct userNode *user = data;
5172 struct nick_info *ni = get_nick_info(user->nick);
5173 if (ni)
5174 nickserv_reclaim(user, ni, nickserv_conf.auto_reclaim_action);
5175 }
5176
5177 static int
5178 check_user_nick(struct userNode *user, UNUSED_ARG(void *extra)) {
5179 struct nick_info *ni;
5180 user->modes &= ~FLAGS_REGNICK;
5181 if (!(ni = get_nick_info(user->nick)))
5182 return 0;
5183 if (user->handle_info == ni->owner) {
5184 user->modes |= FLAGS_REGNICK;
5185 irc_regnick(user);
5186 return 0;
5187 }
5188 if (nickserv_conf.warn_nick_owned)
5189 send_message(user, nickserv, "NSMSG_RECLAIM_WARN", ni->nick, ni->owner->handle);
5190 send_message(user, nickserv, "NSMSG_RECLAIM_HOWTO", ni->owner->handle, nickserv->nick, self->name, ni->owner->handle);
5191 if (nickserv_conf.auto_reclaim_action == RECLAIM_NONE)
5192 return 0;
5193 if (nickserv_conf.auto_reclaim_delay)
5194 timeq_add(now + nickserv_conf.auto_reclaim_delay, nickserv_reclaim_p, user);
5195 else
5196 nickserv_reclaim(user, ni, nickserv_conf.auto_reclaim_action);
5197
5198 return 0;
5199 }
5200
5201 void
5202 handle_account(struct userNode *user, const char *stamp)
5203 {
5204 struct handle_info *hi;
5205 char *colon;
5206
5207 #ifdef WITH_PROTOCOL_P10
5208 time_t timestamp = 0;
5209
5210 colon = strchr(stamp, ':');
5211 if(colon && colon[1])
5212 {
5213 *colon = 0;
5214 timestamp = atoi(colon+1);
5215 }
5216 hi = dict_find(nickserv_handle_dict, stamp, NULL);
5217 if(hi && timestamp && hi->registered != timestamp)
5218 {
5219 log_module(MAIN_LOG, LOG_WARNING, "%s using account %s but timestamp does not match %s is not %s.", user->nick, stamp, ctime(&timestamp),
5220 ctime(&hi->registered));
5221 return;
5222 }
5223 #else
5224 hi = dict_find(nickserv_id_dict, stamp, NULL);
5225 log_module(MAIN_LOG, LOG_WARNING, "Using non-P10 code in accounts, not tested at all!");
5226 #endif
5227
5228 if (hi) {
5229 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
5230 return;
5231 }
5232 set_user_handle_info(user, hi, 0);
5233 } else {
5234 log_module(MAIN_LOG, LOG_WARNING, "%s had unknown account stamp %s.", user->nick, stamp);
5235 }
5236 }
5237
5238 void
5239 handle_nick_change(struct userNode *user, const char *old_nick, UNUSED_ARG(void *extra))
5240 {
5241 struct handle_info *hi;
5242
5243 if ((hi = dict_find(nickserv_allow_auth_dict, old_nick, 0))) {
5244 dict_remove(nickserv_allow_auth_dict, old_nick);
5245 dict_insert(nickserv_allow_auth_dict, user->nick, hi);
5246 }
5247 timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
5248 check_user_nick(user, NULL);
5249 }
5250
5251 void
5252 nickserv_remove_user(struct userNode *user, UNUSED_ARG(struct userNode *killer), UNUSED_ARG(const char *why), UNUSED_ARG(void *extra))
5253 {
5254 dict_remove(nickserv_allow_auth_dict, user->nick);
5255 timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
5256 set_user_handle_info(user, NULL, 0);
5257 }
5258
5259 static struct modcmd *
5260 nickserv_define_func(const char *name, modcmd_func_t func, int min_level, int must_auth, int must_be_qualified)
5261 {
5262 if (min_level > 0) {
5263 char buf[16];
5264 sprintf(buf, "%u", min_level);
5265 if (must_be_qualified) {
5266 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "level", buf, "flags", "+qualified,+loghostmask", NULL);
5267 } else {
5268 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "level", buf, NULL);
5269 }
5270 } else if (min_level == 0) {
5271 if (must_be_qualified) {
5272 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "flags", "+helping", NULL);
5273 } else {
5274 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "flags", "+helping", NULL);
5275 }
5276 } else {
5277 if (must_be_qualified) {
5278 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "flags", "+qualified,+loghostmask", NULL);
5279 } else {
5280 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), NULL);
5281 }
5282 }
5283 }
5284
5285 static void
5286 nickserv_db_cleanup(UNUSED_ARG(void* extra))
5287 {
5288 unreg_del_user_func(nickserv_remove_user, NULL);
5289 userList_clean(&curr_helpers);
5290 policer_params_delete(nickserv_conf.auth_policer_params);
5291 dict_delete(nickserv_handle_dict);
5292 dict_delete(nickserv_nick_dict);
5293 dict_delete(nickserv_opt_dict);
5294 dict_delete(nickserv_allow_auth_dict);
5295 dict_delete(nickserv_email_dict);
5296 dict_delete(nickserv_id_dict);
5297 dict_delete(nickserv_conf.weak_password_dict);
5298 free(auth_func_list);
5299 free(auth_func_list_extra);
5300 free(unreg_func_list);
5301 free(unreg_func_list_extra);
5302 free(rf_list);
5303 free(rf_list_extra);
5304 free(allowauth_func_list);
5305 free(allowauth_func_list_extra);
5306 free(handle_merge_func_list);
5307 free(handle_merge_func_list_extra);
5308 free(failpw_func_list);
5309 free(failpw_func_list_extra);
5310 if (nickserv_conf.valid_handle_regex_set)
5311 regfree(&nickserv_conf.valid_handle_regex);
5312 if (nickserv_conf.valid_nick_regex_set)
5313 regfree(&nickserv_conf.valid_nick_regex);
5314 }
5315
5316 void handle_loc_auth_oper(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle), UNUSED_ARG(void *extra)) {
5317 if (!*nickserv_conf.auto_oper || !user->handle_info)
5318 return;
5319
5320 if (!IsOper(user)) {
5321 if (*nickserv_conf.auto_admin && user->handle_info->opserv_level >= opserv_conf_admin_level()) {
5322 irc_umode(user, nickserv_conf.auto_admin);
5323 irc_sno(0x1, "%s (%s@%s) is now an IRC Administrator",
5324 user->nick, user->ident, user->hostname);
5325 } else if (*nickserv_conf.auto_oper && user->handle_info->opserv_level) {
5326 irc_umode(user, nickserv_conf.auto_oper);
5327 irc_sno(0x1, "%s (%s@%s) is now an IRC Operator",
5328 user->nick, user->ident, user->hostname);
5329 }
5330 }
5331 }
5332
5333 void
5334 init_nickserv(const char *nick)
5335 {
5336 struct chanNode *chan;
5337 unsigned int i;
5338 NS_LOG = log_register_type("NickServ", "file:nickserv.log");
5339 reg_new_user_func(check_user_nick, NULL);
5340 reg_nick_change_func(handle_nick_change, NULL);
5341 reg_del_user_func(nickserv_remove_user, NULL);
5342 reg_account_func(handle_account);
5343 reg_auth_func(handle_loc_auth_oper, NULL);
5344
5345 /* set up handle_inverse_flags */
5346 memset(handle_inverse_flags, 0, sizeof(handle_inverse_flags));
5347 for (i=0; handle_flags[i]; i++) {
5348 handle_inverse_flags[(unsigned char)handle_flags[i]] = i + 1;
5349 flag_access_levels[i] = 0;
5350 }
5351
5352 conf_register_reload(nickserv_conf_read);
5353 nickserv_opt_dict = dict_new();
5354 nickserv_email_dict = dict_new();
5355
5356 dict_set_free_keys(nickserv_email_dict, free);
5357 dict_set_free_data(nickserv_email_dict, nickserv_free_email_addr);
5358
5359 nickserv_module = module_register("NickServ", NS_LOG, "nickserv.help", NULL);
5360 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
5361 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
5362 * a big pain to disable since its nolonger in the config file. ) -Rubin
5363 */
5364 modcmd_register(nickserv_module, "AUTH", cmd_auth, 2, MODCMD_KEEP_BOUND, "flags", "+loghostmask", NULL);
5365 nickserv_define_func("ALLOWAUTH", cmd_allowauth, 0, 1, 0);
5366 nickserv_define_func("REGISTER", cmd_register, -1, 0, 0);
5367 nickserv_define_func("OREGISTER", cmd_oregister, 0, 1, 0);
5368 nickserv_define_func("UNREGISTER", cmd_unregister, -1, 1, 0);
5369 nickserv_define_func("OUNREGISTER", cmd_ounregister, 0, 1, 0);
5370 nickserv_define_func("ADDMASK", cmd_addmask, -1, 1, 0);
5371 nickserv_define_func("OADDMASK", cmd_oaddmask, 0, 1, 0);
5372 nickserv_define_func("DELMASK", cmd_delmask, -1, 1, 0);
5373 nickserv_define_func("ODELMASK", cmd_odelmask, 0, 1, 0);
5374 nickserv_define_func("ADDSSLFP", cmd_addsslfp, -1, 1, 0);
5375 nickserv_define_func("OADDSSLFP", cmd_oaddsslfp, 0, 1, 0);
5376 nickserv_define_func("DELSSLFP", cmd_delsslfp, -1, 1, 0);
5377 nickserv_define_func("ODELSSLFP", cmd_odelsslfp, 0, 1, 0);
5378 nickserv_define_func("PASS", cmd_pass, -1, 1, 0);
5379 nickserv_define_func("SET", cmd_set, -1, 1, 0);
5380 nickserv_define_func("OSET", cmd_oset, 0, 1, 0);
5381 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo, -1, 0, 0);
5382 nickserv_define_func("USERINFO", cmd_userinfo, -1, 1, 0);
5383 nickserv_define_func("RENAME", cmd_rename_handle, -1, 1, 0);
5384 nickserv_define_func("VACATION", cmd_vacation, -1, 1, 0);
5385 nickserv_define_func("MERGE", cmd_merge, 750, 1, 0);
5386 if (!nickserv_conf.disable_nicks) {
5387 /* nick management commands */
5388 nickserv_define_func("REGNICK", cmd_regnick, -1, 1, 0);
5389 nickserv_define_func("OREGNICK", cmd_oregnick, 0, 1, 0);
5390 nickserv_define_func("UNREGNICK", cmd_unregnick, -1, 1, 0);
5391 nickserv_define_func("OUNREGNICK", cmd_ounregnick, 0, 1, 0);
5392 nickserv_define_func("NICKINFO", cmd_nickinfo, -1, 1, 0);
5393 nickserv_define_func("RECLAIM", cmd_reclaim, -1, 1, 0);
5394 }
5395 if (nickserv_conf.email_enabled) {
5396 nickserv_define_func("AUTHCOOKIE", cmd_authcookie, -1, 0, 0);
5397 nickserv_define_func("RESETPASS", cmd_resetpass, -1, 0, 0);
5398 nickserv_define_func("COOKIE", cmd_cookie, -1, 0, 0);
5399 nickserv_define_func("DELCOOKIE", cmd_delcookie, -1, 1, 0);
5400 nickserv_define_func("ODELCOOKIE", cmd_odelcookie, 0, 1, 0);
5401 dict_insert(nickserv_opt_dict, "EMAIL", opt_email);
5402 }
5403 nickserv_define_func("GHOST", cmd_ghost, -1, 1, 0);
5404 /* ignore commands */
5405 nickserv_define_func("ADDIGNORE", cmd_addignore, -1, 1, 0);
5406 nickserv_define_func("OADDIGNORE", cmd_oaddignore, 0, 1, 0);
5407 nickserv_define_func("DELIGNORE", cmd_delignore, -1, 1, 0);
5408 nickserv_define_func("ODELIGNORE", cmd_odelignore, 0, 1, 0);
5409 /* miscellaneous commands */
5410 nickserv_define_func("STATUS", cmd_status, -1, 0, 0);
5411 nickserv_define_func("SEARCH", cmd_search, 100, 1, 0);
5412 nickserv_define_func("SEARCH UNREGISTER", NULL, 800, 1, 0);
5413 nickserv_define_func("MERGEDB", cmd_mergedb, 999, 1, 0);
5414 nickserv_define_func("CHECKPASS", cmd_checkpass, 601, 1, 0);
5415 nickserv_define_func("CHECKEMAIL", cmd_checkemail, 0, 1, 0);
5416 /* other options */
5417 dict_insert(nickserv_opt_dict, "INFO", opt_info);
5418 dict_insert(nickserv_opt_dict, "WIDTH", opt_width);
5419 dict_insert(nickserv_opt_dict, "TABLEWIDTH", opt_tablewidth);
5420 dict_insert(nickserv_opt_dict, "COLOR", opt_color);
5421 dict_insert(nickserv_opt_dict, "PRIVMSG", opt_privmsg);
5422 dict_insert(nickserv_opt_dict, "AUTOHIDE", opt_autohide);
5423 dict_insert(nickserv_opt_dict, "STYLE", opt_style);
5424 dict_insert(nickserv_opt_dict, "PASS", opt_password);
5425 dict_insert(nickserv_opt_dict, "PASSWORD", opt_password);
5426 dict_insert(nickserv_opt_dict, "FLAGS", opt_flags);
5427 dict_insert(nickserv_opt_dict, "ACCESS", opt_level);
5428 dict_insert(nickserv_opt_dict, "LEVEL", opt_level);
5429 dict_insert(nickserv_opt_dict, "EPITHET", opt_epithet);
5430 dict_insert(nickserv_opt_dict, "NOTE", opt_note);
5431 if (nickserv_conf.titlehost_suffix) {
5432 dict_insert(nickserv_opt_dict, "TITLE", opt_title);
5433 dict_insert(nickserv_opt_dict, "FAKEHOST", opt_fakehost);
5434 }
5435 dict_insert(nickserv_opt_dict, "ANNOUNCEMENTS", opt_announcements);
5436 dict_insert(nickserv_opt_dict, "MAXLOGINS", opt_maxlogins);
5437 dict_insert(nickserv_opt_dict, "ADVANCED", opt_advanced);
5438 dict_insert(nickserv_opt_dict, "LANGUAGE", opt_language);
5439 dict_insert(nickserv_opt_dict, "KARMA", opt_karma);
5440
5441 nickserv_handle_dict = dict_new();
5442 dict_set_free_keys(nickserv_handle_dict, free);
5443 dict_set_free_data(nickserv_handle_dict, free_handle_info);
5444
5445 nickserv_id_dict = dict_new();
5446 dict_set_free_keys(nickserv_id_dict, free);
5447
5448 nickserv_nick_dict = dict_new();
5449 dict_set_free_data(nickserv_nick_dict, free);
5450
5451 nickserv_allow_auth_dict = dict_new();
5452
5453 userList_init(&curr_helpers);
5454
5455 if (nick) {
5456 const char *modes = conf_get_data("services/nickserv/modes", RECDB_QSTRING);
5457 nickserv = AddLocalUser(nick, nick, NULL, "Nick Services", modes);
5458 nickserv_service = service_register(nickserv);
5459 }
5460 saxdb_register("NickServ", nickserv_saxdb_read, nickserv_saxdb_write);
5461 reg_exit_func(nickserv_db_cleanup, NULL);
5462 if(nickserv_conf.handle_expire_frequency)
5463 timeq_add(now + nickserv_conf.handle_expire_frequency, expire_handles, NULL);
5464
5465 if(autojoin_channels && nickserv) {
5466 for (i = 0; i < autojoin_channels->used; i++) {
5467 chan = AddChannel(autojoin_channels->list[i], now, "+nt", NULL, NULL);
5468 AddChannelUser(nickserv, chan)->modes |= MODE_CHANOP;
5469 }
5470 }
5471 #ifdef WITH_LDAP
5472 ldap_do_init(nickserv_conf);
5473 #endif
5474
5475 message_register_table(msgtab);
5476 }