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