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