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