]> jfr.im git - irc/evilnet/x3.git/blob - src/nickserv.c
Changed PEON to PAL as some people found it insulting.
[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 register_nick(user->nick, hi);
1116 send_message(user, nickserv, "NSMSG_REGISTER_HN_SUCCESS");
1117 }
1118 }
1119 if (settee && (user != settee)) {
1120 if(user) {
1121 send_message(settee, nickserv, "NSMSG_OREGISTER_VICTIM", user->nick, hi->handle);
1122 }
1123 }
1124 return hi;
1125 }
1126
1127 static void
1128 nickserv_bake_cookie(struct handle_cookie *cookie)
1129 {
1130 cookie->hi->cookie = cookie;
1131 timeq_add(cookie->expires, nickserv_free_cookie, cookie);
1132 }
1133
1134 /* Contributed by the great sneep of afternet ;) */
1135 /* Since this gets used in a URL, we want to avoid stuff that confuses
1136 * email clients such as ] and ?. a-z, 0-9 only.
1137 */
1138 void genpass(char *str, int len)
1139 {
1140 int i = 0;
1141 char c = 0;
1142
1143 for(i = 0; i < len; i++)
1144 {
1145 do
1146 {
1147 c = (char)((float)rand() / (float)RAND_MAX * (float)256);
1148 } while(!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')));
1149 str[i] = c;
1150 }
1151 str[i] = '\0';
1152 return;
1153 }
1154
1155 static void
1156 nickserv_make_cookie(struct userNode *user, struct handle_info *hi, enum cookie_type type, const char *cookie_data, int weblink)
1157 {
1158 struct handle_cookie *cookie;
1159 char subject[128], body[4096], *misc;
1160 const char *netname, *fmt;
1161 int first_time = 0;
1162
1163 if (hi->cookie) {
1164 send_message(user, nickserv, "NSMSG_COOKIE_LIVE", hi->handle);
1165 return;
1166 }
1167
1168 cookie = calloc(1, sizeof(*cookie));
1169 cookie->hi = hi;
1170 cookie->type = type;
1171 cookie->data = cookie_data ? strdup(cookie_data) : NULL;
1172
1173 cookie->expires = now + nickserv_conf.cookie_timeout;
1174 /* Adding dedicated password gen function for more control -Rubin */
1175 genpass(cookie->cookie, 10);
1176 /*
1177 *inttobase64(cookie->cookie, rand(), 5);
1178 *inttobase64(cookie->cookie+5, rand(), 5);
1179 */
1180
1181 netname = nickserv_conf.network_name;
1182 subject[0] = 0;
1183
1184 switch (cookie->type) {
1185 case ACTIVATION:
1186 hi->passwd[0] = 0; /* invalidate password */
1187 send_message(user, nickserv, "NSMSG_USE_COOKIE_REGISTER");
1188 fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_SUBJECT");
1189 snprintf(subject, sizeof(subject), fmt, netname);
1190
1191 if(weblink)
1192 fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_BODY_WEB");
1193 else
1194 fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_BODY");
1195
1196 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1197 first_time = 1;
1198 break;
1199 case PASSWORD_CHANGE:
1200 send_message(user, nickserv, "NSMSG_USE_COOKIE_RESETPASS");
1201 fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1202 snprintf(subject, sizeof(subject), fmt, netname);
1203 if(weblink)
1204 fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1205 else
1206 fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_BODY");
1207 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1208 break;
1209 case EMAIL_CHANGE:
1210 misc = hi->email_addr;
1211 hi->email_addr = cookie->data;
1212 #ifdef stupid_verify_old_email
1213 if (misc) {
1214 send_message(user, nickserv, "NSMSG_USE_COOKIE_EMAIL_2");
1215 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1216 snprintf(subject, sizeof(subject), fmt, netname);
1217 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1218 snprintf(body, sizeof(body), fmt, netname, cookie->cookie+COOKIELEN/2, nickserv->nick, self->name, hi->handle, COOKIELEN/2);
1219 sendmail(nickserv, hi, subject, body, 1);
1220 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1221 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle, COOKIELEN/2, hi->email_addr);
1222 } else {
1223 #endif
1224 send_message(user, nickserv, "NSMSG_USE_COOKIE_EMAIL_1");
1225 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1226 snprintf(subject, sizeof(subject), fmt, netname);
1227 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_BODY");
1228 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1229 sendmail(nickserv, hi, subject, body, 1);
1230 subject[0] = 0;
1231 #ifdef stupid_verify_old_email
1232 }
1233 #endif
1234 hi->email_addr = misc;
1235 break;
1236 case ALLOWAUTH:
1237 fmt = handle_find_message(hi, "NSEMAIL_ALLOWAUTH_SUBJECT");
1238 snprintf(subject, sizeof(subject), fmt, netname);
1239 fmt = handle_find_message(hi, "NSEMAIL_ALLOWAUTH_BODY");
1240 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1241 send_message(user, nickserv, "NSMSG_USE_COOKIE_AUTH");
1242 break;
1243 default:
1244 log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d in nickserv_make_cookie.", cookie->type);
1245 break;
1246 }
1247 if (subject[0])
1248 sendmail(nickserv, hi, subject, body, first_time);
1249 nickserv_bake_cookie(cookie);
1250 }
1251
1252 static void
1253 nickserv_eat_cookie(struct handle_cookie *cookie)
1254 {
1255 cookie->hi->cookie = NULL;
1256 timeq_del(cookie->expires, nickserv_free_cookie, cookie, 0);
1257 nickserv_free_cookie(cookie);
1258 }
1259
1260 static void
1261 nickserv_free_email_addr(void *data)
1262 {
1263 handle_info_list_clean(data);
1264 free(data);
1265 }
1266
1267 static void
1268 nickserv_set_email_addr(struct handle_info *hi, const char *new_email_addr)
1269 {
1270 struct handle_info_list *hil;
1271 /* Remove from old handle_info_list ... */
1272 if (hi->email_addr && (hil = dict_find(nickserv_email_dict, hi->email_addr, 0))) {
1273 handle_info_list_remove(hil, hi);
1274 if (!hil->used) dict_remove(nickserv_email_dict, hil->tag);
1275 hi->email_addr = NULL;
1276 }
1277 /* Add to the new list.. */
1278 if (new_email_addr) {
1279 if (!(hil = dict_find(nickserv_email_dict, new_email_addr, 0))) {
1280 hil = calloc(1, sizeof(*hil));
1281 hil->tag = strdup(new_email_addr);
1282 handle_info_list_init(hil);
1283 dict_insert(nickserv_email_dict, hil->tag, hil);
1284 }
1285 handle_info_list_append(hil, hi);
1286 hi->email_addr = hil->tag;
1287 }
1288 }
1289
1290 static NICKSERV_FUNC(cmd_register)
1291 {
1292 irc_in_addr_t ip;
1293 struct handle_info *hi;
1294 const char *email_addr, *password;
1295 char syncpass[MD5_CRYPT_LENGTH];
1296 int no_auth, weblink;
1297
1298 if (checkDefCon(DEFCON_NO_NEW_NICKS) && !IsOper(user)) {
1299 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf.disable_nicks ? "accounts" : "nicknames");
1300 return 0;
1301 }
1302
1303 if (!IsOper(user) && !dict_size(nickserv_handle_dict)) {
1304 /* Require the first handle registered to belong to someone +o. */
1305 reply("NSMSG_REQUIRE_OPER");
1306 return 0;
1307 }
1308
1309 if (user->handle_info) {
1310 reply("NSMSG_USE_RENAME", user->handle_info->handle);
1311 return 0;
1312 }
1313
1314 if (IsRegistering(user)) {
1315 reply("NSMSG_ALREADY_REGISTERING");
1316 return 0;
1317 }
1318
1319 if (IsStamped(user)) {
1320 /* Unauthenticated users might still have been stamped
1321 previously and could therefore have a hidden host;
1322 do not allow them to register a new account. */
1323 reply("NSMSG_STAMPED_REGISTER");
1324 return 0;
1325 }
1326
1327 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf.email_required);
1328
1329 if(nickserv_conf.force_handles_lowercase)
1330 irc_strtolower(argv[1]);
1331 if (!is_valid_handle(argv[1])) {
1332 reply("NSMSG_BAD_HANDLE", argv[1]);
1333 return 0;
1334 }
1335
1336
1337 if ((argc >= 4) && nickserv_conf.email_enabled) {
1338 struct handle_info_list *hil;
1339 const char *str;
1340
1341 /* Remember email address. */
1342 email_addr = argv[3];
1343
1344 /* Check that the email address looks valid.. */
1345 if (!valid_email(email_addr)) {
1346 reply("NSMSG_BAD_EMAIL_ADDR");
1347 return 0;
1348 }
1349
1350 /* .. and that we are allowed to send to it. */
1351 if ((str = sendmail_prohibited_address(email_addr))) {
1352 reply("NSMSG_EMAIL_PROHIBITED", email_addr, str);
1353 return 0;
1354 }
1355
1356 /* If we do email verify, make sure we don't spam the address. */
1357 if ((hil = dict_find(nickserv_email_dict, email_addr, NULL))) {
1358 unsigned int nn;
1359 for (nn=0; nn<hil->used; nn++) {
1360 if (hil->list[nn]->cookie) {
1361 reply("NSMSG_EMAIL_UNACTIVATED");
1362 return 0;
1363 }
1364 }
1365 if (hil->used >= nickserv_conf.handles_per_email) {
1366 reply("NSMSG_EMAIL_OVERUSED");
1367 return 0;
1368 }
1369 }
1370
1371 no_auth = 1;
1372 } else {
1373 email_addr = 0;
1374 no_auth = 0;
1375 }
1376
1377 password = argv[2];
1378 argv[2] = "****";
1379 /* Webregister hack - send URL instead of IRC cookie
1380 * commands in email
1381 */
1382 if((argc >= 5) && !strcmp(argv[4],"WEBLINK"))
1383 weblink = 1;
1384 else
1385 weblink = 0;
1386 if (!(hi = nickserv_register(user, user, argv[1], password, no_auth)))
1387 return 0;
1388 /* Add any masks they should get. */
1389 if (nickserv_conf.default_hostmask) {
1390 string_list_append(hi->masks, strdup("*@*"));
1391 } else {
1392 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
1393 if (irc_in_addr_is_valid(user->ip) && !irc_pton(&ip, NULL, user->hostname))
1394 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
1395 }
1396
1397 /* If they're the first to register, give them level 1000. */
1398 if (dict_size(nickserv_handle_dict) == 1) {
1399 hi->opserv_level = 1000;
1400 reply("NSMSG_ROOT_HANDLE", argv[1]);
1401 }
1402
1403 /* Set their email address. */
1404 if (email_addr) {
1405 #ifdef WITH_LDAP
1406 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1407 int rc;
1408 if((rc = ldap_do_modify(hi->handle, NULL, email_addr)) != LDAP_SUCCESS) {
1409 /* Falied to update email in ldap, but still
1410 * updated it here.. what should we do? */
1411 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc));
1412 } else {
1413 nickserv_set_email_addr(hi, email_addr);
1414 }
1415 }
1416 else {
1417 nickserv_set_email_addr(hi, email_addr);
1418 }
1419 #else
1420 nickserv_set_email_addr(hi, email_addr);
1421 #endif
1422 }
1423
1424 /* If they need to do email verification, tell them. */
1425 if (no_auth)
1426 nickserv_make_cookie(user, hi, ACTIVATION, hi->passwd, weblink);
1427
1428 /* Set registering flag.. */
1429 user->modes |= FLAGS_REGISTERING;
1430
1431 if (nickserv_conf.sync_log) {
1432 cryptpass(password, syncpass);
1433 /*
1434 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1435 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1436 * -SiRVulcaN
1437 */
1438 SyncLog("REGISTER %s %s %s %s", hi->handle, syncpass, email_addr ? email_addr : "0", user->info);
1439 }
1440
1441 /* this wont work if email is required .. */
1442 process_adduser_pending(user);
1443
1444 return 1;
1445 }
1446
1447 static NICKSERV_FUNC(cmd_oregister)
1448 {
1449 struct userNode *settee = NULL;
1450 struct handle_info *hi;
1451 char* account = NULL;
1452 char* pass = NULL;
1453 char* email = NULL;
1454 char* mask = NULL;
1455 char* nick = NULL;
1456
1457 NICKSERV_MIN_PARMS(3);
1458
1459 account = argv[1];
1460 pass = argv[2];
1461 if(nickserv_conf.force_handles_lowercase)
1462 irc_strtolower(account);
1463 if (nickserv_conf.email_required) {
1464 NICKSERV_MIN_PARMS(4);
1465 email = argv[3];
1466 if (argc >= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1467 if (strchr(argv[4], '@') || argc >= 6) /* If @, its mask not nick */
1468 mask = argv[4];
1469 else
1470 nick = argv[4];
1471 }
1472 if (argc >= 6) {
1473 nick = argv[5];
1474 }
1475 }
1476 else {
1477 if (argc >= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1478 if (strchr(argv[3], '@') || argc >= 5) /* If @, its mask not nick */
1479 mask = argv[3];
1480 else
1481 nick = argv[3];
1482 }
1483 if (argc >= 5) {
1484 nick = argv[4];
1485 }
1486 }
1487 /* If they passed a nick, look for that user.. */
1488 if (nick && !(settee = GetUserH(nick))) {
1489 reply("MSG_NICK_UNKNOWN", argv[4]);
1490 return 0;
1491 }
1492 /* If the setee is already authed, we cant add a 2nd account for them.. */
1493 if (settee && settee->handle_info) {
1494 reply("NSMSG_USER_PREV_AUTH", settee->nick);
1495 return 0;
1496 }
1497 /* If there is no default mask in the conf, and they didn't pass a mask,
1498 * but we did find a user by nick, generate the mask */
1499 if (!mask) {
1500 if (nickserv_conf.default_hostmask)
1501 mask = "*@*";
1502 else if (settee)
1503 mask = generate_hostmask(settee, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
1504 else {
1505 reply("NSMSG_REGISTER_BAD_NICKMASK");
1506 return 0;
1507 }
1508 }
1509
1510 if (!(hi = nickserv_register(user, settee, account, pass, 0))) {
1511 return 0; /* error reply handled by above */
1512 }
1513 if (email) {
1514 #ifdef WITH_LDAP
1515 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1516 int rc;
1517 if((rc = ldap_do_modify(hi->handle, NULL, email)) != LDAP_SUCCESS) {
1518 /* Falied to update email in ldap, but still
1519 * updated it here.. what should we do? */
1520 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc));
1521 } else {
1522 nickserv_set_email_addr(hi, email);
1523 }
1524 }
1525 else {
1526 nickserv_set_email_addr(hi, email);
1527 }
1528 #else
1529 nickserv_set_email_addr(hi, email);
1530 #endif
1531 }
1532 if (mask) {
1533 char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
1534 string_list_append(hi->masks, mask_canonicalized);
1535 }
1536
1537 if (nickserv_conf.sync_log)
1538 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, email ? email : "@", user->info); /* Send just @ for email if none */
1539 return 1;
1540 }
1541
1542 static int
1543 nickserv_ignore(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, char *mask)
1544 {
1545 unsigned int i;
1546 struct userNode *target;
1547 char *new_mask = strdup(pretty_mask(mask));
1548 for (i=0; i<hi->ignores->used; i++) {
1549 if (!irccasecmp(new_mask, hi->ignores->list[i])) {
1550 reply("NSMSG_ADDIGNORE_ALREADY", new_mask);
1551 free(new_mask);
1552 return 0;
1553 }
1554 }
1555 string_list_append(hi->ignores, new_mask);
1556 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask);
1557
1558 for (target = hi->users; target; target = target->next_authed) {
1559 irc_silence(target, new_mask, 1);
1560 }
1561 return 1;
1562 }
1563
1564 static NICKSERV_FUNC(cmd_addignore)
1565 {
1566 NICKSERV_MIN_PARMS(2);
1567
1568 return nickserv_ignore(cmd, user, user->handle_info, argv[1]);
1569 }
1570
1571 static NICKSERV_FUNC(cmd_oaddignore)
1572 {
1573 struct handle_info *hi;
1574
1575 NICKSERV_MIN_PARMS(3);
1576 if (!(hi = get_victim_oper(cmd, user, argv[1])))
1577 return 0;
1578
1579 return nickserv_ignore(cmd, user, hi, argv[2]);
1580 }
1581
1582 static int
1583 nickserv_delignore(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, char *del_mask)
1584 {
1585 unsigned int i;
1586 struct userNode *target;
1587 char *pmask = strdup(pretty_mask(del_mask));
1588 for (i=0; i<hi->ignores->used; i++) {
1589 if (!strcmp(pmask, hi->ignores->list[i]) || !strcmp(del_mask, hi->ignores->list[i])) {
1590 char *old_mask = hi->ignores->list[i];
1591 hi->ignores->list[i] = hi->ignores->list[--hi->ignores->used];
1592 reply("NSMSG_DELMASK_SUCCESS", old_mask);
1593 for (target = hi->users; target; target = target->next_authed) {
1594 irc_silence(target, old_mask, 0);
1595 }
1596 free(old_mask);
1597 free(pmask);
1598 return 1;
1599 }
1600 }
1601 reply("NSMSG_DELMASK_NOT_FOUND");
1602 return 0;
1603 }
1604
1605 static NICKSERV_FUNC(cmd_delignore)
1606 {
1607 NICKSERV_MIN_PARMS(2);
1608 return nickserv_delignore(cmd, user, user->handle_info, argv[1]);
1609 }
1610
1611 static NICKSERV_FUNC(cmd_odelignore)
1612 {
1613 struct handle_info *hi;
1614 NICKSERV_MIN_PARMS(3);
1615 if (!(hi = get_victim_oper(cmd, user, argv[1])))
1616 return 0;
1617 return nickserv_delignore(cmd, user, hi, argv[2]);
1618 }
1619
1620 static NICKSERV_FUNC(cmd_handleinfo)
1621 {
1622 char buff[400];
1623 unsigned int i, pos=0, herelen;
1624 struct userNode *target, *next_un;
1625 struct handle_info *hi;
1626 const char *nsmsg_none;
1627
1628 if (argc < 2) {
1629 if (!(hi = user->handle_info)) {
1630 reply("NSMSG_MUST_AUTH");
1631 return 0;
1632 }
1633 } else if (!(hi = modcmd_get_handle_info(user, argv[1]))) {
1634 return 0;
1635 }
1636
1637 nsmsg_none = handle_find_message(hi, "MSG_NONE");
1638 reply("NSMSG_HANDLEINFO_ON", hi->handle);
1639 reply("MSG_BAR");
1640 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi->registered));
1641
1642 if (!hi->users) {
1643 intervalString(buff, now - hi->lastseen, user->handle_info);
1644 reply("NSMSG_HANDLEINFO_LASTSEEN", buff);
1645 } else {
1646 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1647 }
1648
1649 reply("NSMSG_HANDLEINFO_INFOLINE", (hi->infoline ? hi->infoline : nsmsg_none));
1650 if (HANDLE_FLAGGED(hi, FROZEN))
1651 reply("NSMSG_HANDLEINFO_VACATION");
1652
1653 if (oper_has_access(user, cmd->parent->bot, 0, 1)) {
1654 struct do_not_register *dnr;
1655 if ((dnr = chanserv_is_dnr(NULL, hi)))
1656 reply("NSMSG_HANDLEINFO_DNR", dnr->setter, dnr->reason);
1657 if (!oper_outranks(cmd, user, hi))
1658 return 1;
1659 } else if (hi != user->handle_info) {
1660 reply("NSMSG_HANDLEINFO_END");
1661 return 1;
1662 }
1663
1664 if (nickserv_conf.email_enabled)
1665 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user, hi));
1666
1667 if (hi->cookie) {
1668 const char *type;
1669 switch (hi->cookie->type) {
1670 case ACTIVATION: type = "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1671 case PASSWORD_CHANGE: type = "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1672 case EMAIL_CHANGE: type = "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1673 case ALLOWAUTH: type = "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1674 default: type = "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1675 }
1676 reply(type);
1677 }
1678
1679 if (hi->flags) {
1680 unsigned long flen = 1;
1681 char flags[34]; /* 32 bits possible plus '+' and '\0' */
1682 flags[0] = '+';
1683 for (i=0, flen=1; handle_flags[i]; i++)
1684 if (hi->flags & 1 << i)
1685 flags[flen++] = handle_flags[i];
1686 flags[flen] = 0;
1687 reply("NSMSG_HANDLEINFO_FLAGS", flags);
1688 } else {
1689 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none);
1690 }
1691
1692 if (HANDLE_FLAGGED(hi, SUPPORT_HELPER)
1693 || HANDLE_FLAGGED(hi, NETWORK_HELPER)
1694 || (hi->opserv_level > 0)) {
1695 reply("NSMSG_HANDLEINFO_EPITHET", (hi->epithet ? hi->epithet : nsmsg_none));
1696 }
1697
1698 if (IsHelping(user) || IsOper(user))
1699 {
1700 if (hi->note)
1701 {
1702 char date[64];
1703 strftime(date, 64, "%b %d %Y", localtime(&hi->note->date));
1704 reply("NSMSG_HANDLEINFO_NOTE", hi->note->setter, date, hi->note->note);
1705 }
1706 }
1707
1708 if (hi->fakehost)
1709 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi->fakehost ? hi->fakehost : handle_find_message(hi, "MSG_NONE")));
1710
1711 if (hi->last_quit_host[0])
1712 reply("NSMSG_HANDLEINFO_LAST_HOST", hi->last_quit_host);
1713 else
1714 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1715
1716 if (nickserv_conf.disable_nicks) {
1717 /* nicks disabled; don't show anything about registered nicks */
1718 } else if (hi->nicks) {
1719 struct nick_info *ni, *next_ni;
1720 for (ni = hi->nicks; ni; ni = next_ni) {
1721 herelen = strlen(ni->nick);
1722 if (pos + herelen + 1 > ArrayLength(buff)) {
1723 next_ni = ni;
1724 goto print_nicks_buff;
1725 } else {
1726 next_ni = ni->next;
1727 }
1728 memcpy(buff+pos, ni->nick, herelen);
1729 pos += herelen; buff[pos++] = ' ';
1730 if (!next_ni) {
1731 print_nicks_buff:
1732 buff[pos-1] = 0;
1733 reply("NSMSG_HANDLEINFO_NICKS", buff);
1734 pos = 0;
1735 }
1736 }
1737 } else {
1738 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none);
1739 }
1740
1741 if (hi->masks->used) {
1742 for (i=0; i < hi->masks->used; i++) {
1743 herelen = strlen(hi->masks->list[i]);
1744 if (pos + herelen + 1 > ArrayLength(buff)) {
1745 i--;
1746 goto print_mask_buff;
1747 }
1748 memcpy(buff+pos, hi->masks->list[i], herelen);
1749 pos += herelen; buff[pos++] = ' ';
1750 if (i+1 == hi->masks->used) {
1751 print_mask_buff:
1752 buff[pos-1] = 0;
1753 reply("NSMSG_HANDLEINFO_MASKS", buff);
1754 pos = 0;
1755 }
1756 }
1757 } else {
1758 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none);
1759 }
1760
1761 if (hi->ignores->used) {
1762 for (i=0; i < hi->ignores->used; i++) {
1763 herelen = strlen(hi->ignores->list[i]);
1764 if (pos + herelen + 1 > ArrayLength(buff)) {
1765 i--;
1766 goto print_ignore_buff;
1767 }
1768 memcpy(buff+pos, hi->ignores->list[i], herelen);
1769 pos += herelen; buff[pos++] = ' ';
1770 if (i+1 == hi->ignores->used) {
1771 print_ignore_buff:
1772 buff[pos-1] = 0;
1773 reply("NSMSG_HANDLEINFO_IGNORES", buff);
1774 pos = 0;
1775 }
1776 }
1777 } else {
1778 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none);
1779 }
1780
1781 if (hi->channels) {
1782 struct userData *channel, *next;
1783 char *name;
1784
1785 for (channel = hi->channels; channel; channel = next) {
1786 next = channel->u_next;
1787 name = channel->channel->channel->name;
1788 herelen = strlen(name);
1789 if (pos + herelen + 7 > ArrayLength(buff)) {
1790 next = channel;
1791 goto print_chans_buff;
1792 }
1793 if (IsUserSuspended(channel))
1794 buff[pos++] = '-';
1795 pos += sprintf(buff+pos, "%s:%s ", user_level_name_from_level(channel->access), name);
1796 if (next == NULL) {
1797 print_chans_buff:
1798 buff[pos-1] = 0;
1799 reply("NSMSG_HANDLEINFO_CHANNELS", buff);
1800 pos = 0;
1801 }
1802 }
1803 } else {
1804 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none);
1805 }
1806
1807 for (target = hi->users; target; target = next_un) {
1808 herelen = strlen(target->nick);
1809 if (pos + herelen + 1 > ArrayLength(buff)) {
1810 next_un = target;
1811 goto print_cnick_buff;
1812 } else {
1813 next_un = target->next_authed;
1814 }
1815 memcpy(buff+pos, target->nick, herelen);
1816 pos += herelen; buff[pos++] = ' ';
1817 if (!next_un) {
1818 print_cnick_buff:
1819 buff[pos-1] = 0;
1820 reply("NSMSG_HANDLEINFO_CURRENT", buff);
1821 pos = 0;
1822 }
1823 }
1824
1825 reply("NSMSG_HANDLEINFO_END");
1826 return 1;
1827 }
1828
1829 static NICKSERV_FUNC(cmd_userinfo)
1830 {
1831 struct userNode *target;
1832
1833 NICKSERV_MIN_PARMS(2);
1834 if (!(target = GetUserH(argv[1]))) {
1835 reply("MSG_NICK_UNKNOWN", argv[1]);
1836 return 0;
1837 }
1838 if (target->handle_info)
1839 reply("NSMSG_USERINFO_AUTHED_AS", target->nick, target->handle_info->handle);
1840 else
1841 reply("NSMSG_USERINFO_NOT_AUTHED", target->nick);
1842 return 1;
1843 }
1844
1845 static NICKSERV_FUNC(cmd_nickinfo)
1846 {
1847 struct nick_info *ni;
1848
1849 NICKSERV_MIN_PARMS(2);
1850 if (!(ni = get_nick_info(argv[1]))) {
1851 reply("MSG_NICK_UNKNOWN", argv[1]);
1852 return 0;
1853 }
1854 reply("NSMSG_NICKINFO_OWNER", ni->nick, ni->owner->handle);
1855 return 1;
1856 }
1857
1858 static NICKSERV_FUNC(cmd_rename_handle)
1859 {
1860 struct handle_info *hi;
1861 struct userNode *uNode;
1862 char *old_handle;
1863 unsigned int nn;
1864
1865 NICKSERV_MIN_PARMS(3);
1866 if(nickserv_conf.force_handles_lowercase)
1867 irc_strtolower(argv[2]);
1868 if (!(hi = get_victim_oper(cmd, user, argv[1])))
1869 return 0;
1870 if (!is_valid_handle(argv[2])) {
1871 reply("NSMSG_FAIL_RENAME", argv[1], argv[2]);
1872 return 0;
1873 }
1874 if (get_handle_info(argv[2])) {
1875 reply("NSMSG_HANDLE_EXISTS", argv[2]);
1876 return 0;
1877 }
1878 if(strlen(argv[2]) > 30)
1879 {
1880 reply("NMSG_HANDLE_TOLONG", argv[2], 30);
1881 return 0;
1882 }
1883 #ifdef WITH_LDAP
1884 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1885 int rc;
1886 if( (rc = ldap_rename_account(hi->handle, argv[2])) != LDAP_SUCCESS) {
1887 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
1888 return 0;
1889 }
1890 }
1891 #endif
1892
1893 dict_remove2(nickserv_handle_dict, old_handle = hi->handle, 1);
1894 hi->handle = strdup(argv[2]);
1895 dict_insert(nickserv_handle_dict, hi->handle, hi);
1896 for (nn=0; nn<rf_list_used; nn++)
1897 rf_list[nn](hi, old_handle);
1898
1899 if (nickserv_conf.sync_log) {
1900 for (uNode = hi->users; uNode; uNode = uNode->next_authed)
1901 irc_rename(uNode, hi->handle);
1902
1903 SyncLog("RENAME %s %s", old_handle, hi->handle);
1904 }
1905
1906 reply("NSMSG_HANDLE_CHANGED", old_handle, hi->handle);
1907 global_message_args(MESSAGE_RECIPIENT_OPERS, "NSMSG_ACCOUNT_RENAMED",
1908 user->handle_info->handle, old_handle, hi->handle);
1909
1910 free(old_handle);
1911 return 1;
1912 }
1913
1914 static failpw_func_t *failpw_func_list;
1915 static unsigned int failpw_func_size = 0, failpw_func_used = 0;
1916
1917 void
1918 reg_failpw_func(failpw_func_t func)
1919 {
1920 if (failpw_func_used == failpw_func_size) {
1921 if (failpw_func_size) {
1922 failpw_func_size <<= 1;
1923 failpw_func_list = realloc(failpw_func_list, failpw_func_size*sizeof(failpw_func_t));
1924 } else {
1925 failpw_func_size = 8;
1926 failpw_func_list = malloc(failpw_func_size*sizeof(failpw_func_t));
1927 }
1928 }
1929 failpw_func_list[failpw_func_used++] = func;
1930 }
1931
1932 /*
1933 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1934 *
1935 * called by nefariouses enhanced AC login-on-connect code
1936 *
1937 */
1938 struct handle_info *loc_auth(char *handle, char *password, char *userhost)
1939 {
1940 int pw_arg, used, maxlogins;
1941 unsigned int ii;
1942 int wildmask = 0;
1943 struct handle_info *hi;
1944 struct userNode *other;
1945 #ifdef WITH_LDAP
1946 int ldap_result = LDAP_SUCCESS;
1947 char *email = NULL;
1948 #endif
1949
1950 hi = dict_find(nickserv_handle_dict, handle, NULL);
1951 pw_arg = 2;
1952
1953 #ifdef WITH_LDAP
1954 if(nickserv_conf.ldap_enable) {
1955 ldap_result = ldap_check_auth(handle, password);
1956 if(ldap_result != LDAP_SUCCESS) {
1957 return NULL;
1958 }
1959 }
1960 #else
1961 if (!hi) {
1962 return NULL;
1963 }
1964
1965 if (!checkpass(password, hi->passwd)) {
1966 return NULL;
1967 }
1968 #endif
1969 #ifdef WITH_LDAP
1970 /* ldap libs are present but we are not using them... */
1971 if( !nickserv_conf.ldap_enable ) {
1972 if (!hi) {
1973 return NULL;
1974 }
1975 if (!checkpass(password, hi->passwd)) {
1976 return NULL;
1977 }
1978 }
1979 else if( (!hi) && ldap_result == LDAP_SUCCESS && nickserv_conf.ldap_autocreate) {
1980 /* user not found, but authed to ldap successfully..
1981 * create the account.
1982 */
1983 char *mask;
1984 int rc;
1985
1986 /* Add a *@* mask */
1987 /* TODO if userhost is not null, build mask based on that. */
1988 if(nickserv_conf.default_hostmask)
1989 mask = "*@*";
1990 else
1991 return NULL; /* They dont have a *@* mask so they can't loc */
1992
1993 if(!(hi = nickserv_register(NULL, NULL, handle, password, 0))) {
1994 return 0; /* couldn't add the user for some reason */
1995 }
1996
1997 if((rc = ldap_get_user_info(handle, &email) != LDAP_SUCCESS))
1998 {
1999 if(nickserv_conf.email_required) {
2000 return 0;
2001 }
2002 }
2003 if(email) {
2004 nickserv_set_email_addr(hi, email);
2005 free(email);
2006 }
2007 if(mask) {
2008 char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
2009 string_list_append(hi->masks, mask_canonicalized);
2010 }
2011 if(nickserv_conf.sync_log)
2012 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, "@", handle);
2013 }
2014 #endif
2015
2016 /* Still no account, so just fail out */
2017 if (!hi) {
2018 return NULL;
2019 }
2020
2021 /* We don't know the users hostname, or anything because they
2022 * havn't registered yet. So we can only allow LOC if your
2023 * account has *@* as a hostmask.
2024 *
2025 * UPDATE: New nefarious LOC supports u@h
2026 */
2027 if(userhost) {
2028 char *buf;
2029 char *ident;
2030 char *realhost;
2031 char *ip;
2032 char *uh;
2033 char *ui;
2034
2035 buf = strdup(userhost);
2036 ident = mysep(&buf, "@");
2037 realhost = mysep(&buf, ":");
2038 ip = mysep(&buf, ":");
2039 if(!ip || !realhost || !ident) {
2040 free(buf);
2041 return NULL; /* Invalid AC request, just quit */
2042 }
2043 uh = malloc(strlen(userhost));
2044 ui = malloc(strlen(userhost));
2045 sprintf(uh, "%s@%s", ident, realhost);
2046 sprintf(ui, "%s@%s", ident, ip);
2047 for (ii=0; ii<hi->masks->used; ii++)
2048 {
2049 if(match_ircglob(uh, hi->masks->list[ii])
2050 || match_ircglob(ui, hi->masks->list[ii]))
2051 {
2052 wildmask++;
2053 break;
2054 }
2055 }
2056 free(buf);
2057 free(uh);
2058 free(ui);
2059 }
2060 else {
2061
2062 for (ii=0; ii<hi->masks->used; ii++)
2063 {
2064 if (!strcmp(hi->masks->list[ii], "*@*"))
2065 {
2066 wildmask++;
2067 break;
2068 }
2069 }
2070 }
2071 if(wildmask < 1)
2072 return NULL;
2073
2074 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
2075 return NULL;
2076 }
2077
2078 maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
2079 for (used = 0, other = hi->users; other; other = other->next_authed) {
2080 if (++used >= maxlogins) {
2081 return NULL;
2082 }
2083 }
2084 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2085 return hi;
2086 }
2087
2088 static NICKSERV_FUNC(cmd_auth)
2089 {
2090 int pw_arg, used, maxlogins;
2091 struct handle_info *hi;
2092 const char *passwd;
2093 struct userNode *other;
2094 #ifdef WITH_LDAP
2095 int ldap_result = LDAP_OTHER;
2096 char *email = NULL;
2097 #endif
2098
2099 if (user->handle_info) {
2100 reply("NSMSG_ALREADY_AUTHED", user->handle_info->handle);
2101 return 0;
2102 }
2103 if (IsStamped(user)) {
2104 /* Unauthenticated users might still have been stamped
2105 previously and could therefore have a hidden host;
2106 do not allow them to authenticate. */
2107 reply("NSMSG_STAMPED_AUTH");
2108 return 0;
2109 }
2110 if (argc == 3) {
2111 #ifdef WITH_LDAP
2112 if(strchr(argv[1], '<') || strchr(argv[1], '>')) {
2113 reply("NSMSG_NO_ANGLEBRACKETS");
2114 return 0;
2115 }
2116 if (!is_valid_handle(argv[1])) {
2117 reply("NSMSG_BAD_HANDLE", argv[1]);
2118 return 0;
2119 }
2120
2121 if(nickserv_conf.ldap_enable) {
2122 ldap_result = ldap_check_auth(argv[1], argv[2]);
2123 /* Get the users email address and update it */
2124 if(ldap_result == LDAP_SUCCESS) {
2125 int rc;
2126 if((rc = ldap_get_user_info(argv[1], &email) != LDAP_SUCCESS))
2127 {
2128 if(nickserv_conf.email_required) {
2129 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc));
2130 return 0;
2131 }
2132 }
2133 }
2134 else if(ldap_result != LDAP_INVALID_CREDENTIALS) {
2135 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result));
2136 return 0;
2137 }
2138 }
2139
2140 #endif
2141 hi = dict_find(nickserv_handle_dict, argv[1], NULL);
2142 pw_arg = 2;
2143 } else if (argc == 2 && !nickserv_conf.ldap_enable) {
2144 if (nickserv_conf.disable_nicks) {
2145 if (!(hi = get_handle_info(user->nick))) {
2146 reply("NSMSG_HANDLE_NOT_FOUND");
2147 return 0;
2148 }
2149 } else {
2150 /* try to look up their handle from their nick */
2151 /* TODO: handle ldap auth on nickserv style networks, too */
2152 struct nick_info *ni;
2153 ni = get_nick_info(user->nick);
2154 if (!ni) {
2155 reply("NSMSG_NICK_NOT_REGISTERED", user->nick);
2156 return 0;
2157 }
2158 hi = ni->owner;
2159 }
2160 pw_arg = 1;
2161 } else {
2162 reply("MSG_MISSING_PARAMS", argv[0]);
2163 svccmd_send_help_brief(user, nickserv, cmd);
2164 return 0;
2165 }
2166 if (!hi) {
2167 #ifdef WITH_LDAP
2168 if(nickserv_conf.ldap_enable && ldap_result == LDAP_SUCCESS && nickserv_conf.ldap_autocreate) {
2169 /* user not found, but authed to ldap successfully..
2170 * create the account.
2171 */
2172 char *mask;
2173 if(!(hi = nickserv_register(user, NULL, argv[1], argv[2], 0))) {
2174 reply("NSMSG_UNABLE_TO_ADD");
2175 return 0; /* couldn't add the user for some reason */
2176 }
2177 /* Add a *@* mask */
2178 if(nickserv_conf.default_hostmask)
2179 mask = "*@*";
2180 else
2181 mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
2182
2183 if(mask) {
2184 char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
2185 string_list_append(hi->masks, mask_canonicalized);
2186 }
2187 if(email) {
2188 nickserv_set_email_addr(hi, email);
2189 free(email);
2190 }
2191 if(nickserv_conf.sync_log)
2192 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, email ? email : "@", user->info);
2193 }
2194 else {
2195 #endif
2196 reply("NSMSG_HANDLE_NOT_FOUND");
2197 return 0;
2198 #ifdef WITH_LDAP
2199 }
2200 #endif
2201 }
2202 /* Responses from here on look up the language used by the handle they asked about. */
2203 passwd = argv[pw_arg];
2204 if (!valid_user_for(user, hi)) {
2205 if (hi->email_addr && nickserv_conf.email_enabled)
2206 send_message_type(4, user, cmd->parent->bot,
2207 handle_find_message(hi, "NSMSG_USE_AUTHCOOKIE"),
2208 hi->handle);
2209 else
2210 send_message_type(4, user, cmd->parent->bot,
2211 handle_find_message(hi, "NSMSG_HOSTMASK_INVALID"),
2212 hi->handle);
2213 argv[pw_arg] = "BADMASK";
2214 return 1;
2215 }
2216 #ifdef WITH_LDAP
2217 if( ( nickserv_conf.ldap_enable && ldap_result == LDAP_INVALID_CREDENTIALS ) ||
2218 ( (!nickserv_conf.ldap_enable) && (!checkpass(passwd, hi->passwd)) ) ) {
2219 #else
2220 if (!checkpass(passwd, hi->passwd)) {
2221 #endif
2222 unsigned int n;
2223 send_message_type(4, user, cmd->parent->bot,
2224 handle_find_message(hi, "NSMSG_PASSWORD_INVALID"));
2225 argv[pw_arg] = "BADPASS";
2226 for (n=0; n<failpw_func_used; n++) failpw_func_list[n](user, hi);
2227 if (nickserv_conf.autogag_enabled) {
2228 if (!user->auth_policer.params) {
2229 user->auth_policer.last_req = now;
2230 user->auth_policer.params = nickserv_conf.auth_policer_params;
2231 }
2232 if (!policer_conforms(&user->auth_policer, now, 1.0)) {
2233 char *hostmask;
2234 hostmask = generate_hostmask(user, GENMASK_STRICT_HOST|GENMASK_BYIP|GENMASK_NO_HIDING);
2235 log_module(NS_LOG, LOG_INFO, "%s auto-gagged for repeated password guessing.", hostmask);
2236 gag_create(hostmask, nickserv->nick, "Repeated password guessing.", now+nickserv_conf.autogag_duration);
2237 free(hostmask);
2238 argv[pw_arg] = "GAGGED";
2239 }
2240 }
2241 return 1;
2242 }
2243 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
2244 send_message_type(4, user, cmd->parent->bot,
2245 handle_find_message(hi, "NSMSG_HANDLE_SUSPENDED"));
2246 argv[pw_arg] = "SUSPENDED";
2247 return 1;
2248 }
2249 maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
2250 for (used = 0, other = hi->users; other; other = other->next_authed) {
2251 if (++used >= maxlogins) {
2252 send_message_type(4, user, cmd->parent->bot,
2253 handle_find_message(hi, "NSMSG_MAX_LOGINS"),
2254 maxlogins);
2255 argv[pw_arg] = "MAXLOGINS";
2256 return 1;
2257 }
2258 }
2259
2260 set_user_handle_info(user, hi, 1);
2261 if (nickserv_conf.email_required && !hi->email_addr)
2262 reply("NSMSG_PLEASE_SET_EMAIL");
2263 if (!is_secure_password(hi->handle, passwd, NULL))
2264 reply("NSMSG_WEAK_PASSWORD");
2265 if (hi->passwd[0] != '$')
2266 cryptpass(passwd, hi->passwd);
2267
2268 /* If a channel was waiting for this user to auth,
2269 * finish adding them */
2270 process_adduser_pending(user);
2271
2272 reply("NSMSG_AUTH_SUCCESS");
2273
2274
2275 /* Set +x if autohide is on */
2276 if(HANDLE_FLAGGED(hi, AUTOHIDE))
2277 irc_umode(user, "+x");
2278
2279 if(!IsOper(user)) /* If they arnt already opered.. */
2280 {
2281 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2282 if( nickserv_conf.auto_admin[0] && hi->opserv_level >= opserv_conf_admin_level())
2283 {
2284 irc_umode(user,nickserv_conf.auto_admin);
2285 reply("NSMSG_AUTO_OPER_ADMIN");
2286 }
2287 else if (nickserv_conf.auto_oper[0] && hi->opserv_level > 0)
2288 {
2289 irc_umode(user,nickserv_conf.auto_oper);
2290 reply("NSMSG_AUTO_OPER");
2291 }
2292 }
2293
2294 /* Wipe out the pass for the logs */
2295 argv[pw_arg] = "****";
2296 return 1;
2297 }
2298
2299 static allowauth_func_t *allowauth_func_list;
2300 static unsigned int allowauth_func_size = 0, allowauth_func_used = 0;
2301
2302 void
2303 reg_allowauth_func(allowauth_func_t func)
2304 {
2305 if (allowauth_func_used == allowauth_func_size) {
2306 if (allowauth_func_size) {
2307 allowauth_func_size <<= 1;
2308 allowauth_func_list = realloc(allowauth_func_list, allowauth_func_size*sizeof(allowauth_func_t));
2309 } else {
2310 allowauth_func_size = 8;
2311 allowauth_func_list = malloc(allowauth_func_size*sizeof(allowauth_func_t));
2312 }
2313 }
2314 allowauth_func_list[allowauth_func_used++] = func;
2315 }
2316
2317 static NICKSERV_FUNC(cmd_allowauth)
2318 {
2319 struct userNode *target;
2320 struct handle_info *hi;
2321 unsigned int n;
2322
2323 NICKSERV_MIN_PARMS(2);
2324 if (!(target = GetUserH(argv[1]))) {
2325 reply("MSG_NICK_UNKNOWN", argv[1]);
2326 return 0;
2327 }
2328 if (target->handle_info) {
2329 reply("NSMSG_USER_PREV_AUTH", target->nick);
2330 return 0;
2331 }
2332 if (IsStamped(target)) {
2333 /* Unauthenticated users might still have been stamped
2334 previously and could therefore have a hidden host;
2335 do not allow them to authenticate to an account. */
2336 reply("NSMSG_USER_PREV_STAMP", target->nick);
2337 return 0;
2338 }
2339 if (argc == 2)
2340 hi = NULL;
2341 else if (!(hi = get_handle_info(argv[2]))) {
2342 reply("MSG_HANDLE_UNKNOWN", argv[2]);
2343 return 0;
2344 }
2345 if (hi) {
2346 if (hi->opserv_level > user->handle_info->opserv_level) {
2347 reply("MSG_USER_OUTRANKED", hi->handle);
2348 return 0;
2349 }
2350 if (((hi->flags & (HI_FLAG_SUPPORT_HELPER|HI_FLAG_NETWORK_HELPER))
2351 || (hi->opserv_level > 0))
2352 && ((argc < 4) || irccasecmp(argv[3], "staff"))) {
2353 reply("NSMSG_ALLOWAUTH_STAFF", hi->handle);
2354 return 0;
2355 }
2356 dict_insert(nickserv_allow_auth_dict, target->nick, hi);
2357 reply("NSMSG_AUTH_ALLOWED", target->nick, hi->handle);
2358 send_message(target, nickserv, "NSMSG_AUTH_ALLOWED_MSG", hi->handle, hi->handle);
2359 if (nickserv_conf.email_enabled)
2360 send_message(target, nickserv, "NSMSG_AUTH_ALLOWED_EMAIL");
2361 } else {
2362 if (dict_remove(nickserv_allow_auth_dict, target->nick))
2363 reply("NSMSG_AUTH_NORMAL_ONLY", target->nick);
2364 else
2365 reply("NSMSG_AUTH_UNSPECIAL", target->nick);
2366 }
2367 for (n=0; n<allowauth_func_used; n++)
2368 allowauth_func_list[n](user, target, hi);
2369 return 1;
2370 }
2371
2372 static NICKSERV_FUNC(cmd_authcookie)
2373 {
2374 struct handle_info *hi;
2375
2376 NICKSERV_MIN_PARMS(2);
2377 if (user->handle_info) {
2378 reply("NSMSG_ALREADY_AUTHED", user->handle_info->handle);
2379 return 0;
2380 }
2381 if (IsStamped(user)) {
2382 /* Unauthenticated users might still have been stamped
2383 previously and could therefore have a hidden host;
2384 do not allow them to authenticate to an account. */
2385 reply("NSMSG_STAMPED_AUTHCOOKIE");
2386 return 0;
2387 }
2388 if (!(hi = get_handle_info(argv[1]))) {
2389 reply("MSG_HANDLE_UNKNOWN", argv[1]);
2390 return 0;
2391 }
2392 if (!hi->email_addr) {
2393 reply("MSG_SET_EMAIL_ADDR");
2394 return 0;
2395 }
2396 nickserv_make_cookie(user, hi, ALLOWAUTH, NULL, 0);
2397 return 1;
2398 }
2399
2400 static NICKSERV_FUNC(cmd_delcookie)
2401 {
2402 struct handle_info *hi;
2403
2404 hi = user->handle_info;
2405 if (!hi->cookie) {
2406 reply("NSMSG_NO_COOKIE");
2407 return 0;
2408 }
2409 switch (hi->cookie->type) {
2410 case ACTIVATION:
2411 case EMAIL_CHANGE:
2412 reply("NSMSG_MUST_TIME_OUT");
2413 break;
2414 default:
2415 nickserv_eat_cookie(hi->cookie);
2416 reply("NSMSG_ATE_COOKIE");
2417 break;
2418 }
2419 return 1;
2420 }
2421
2422 static NICKSERV_FUNC(cmd_odelcookie)
2423 {
2424 struct handle_info *hi;
2425
2426 NICKSERV_MIN_PARMS(2);
2427
2428 if (!(hi = get_victim_oper(cmd, user, argv[1])))
2429 return 0;
2430
2431 if (!hi->cookie) {
2432 reply("NSMSG_NO_COOKIE_FOREIGN", hi->handle);
2433 return 0;
2434 }
2435
2436 switch (hi->cookie->type) {
2437 case ACTIVATION:
2438 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2439 if (nickserv_conf.sync_log)
2440 SyncLog("ACCOUNTACC %s", hi->handle);
2441 break;
2442 case PASSWORD_CHANGE:
2443 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2444 if (nickserv_conf.sync_log)
2445 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
2446 break;
2447 case EMAIL_CHANGE:
2448 if (!hi->email_addr && nickserv_conf.sync_log) {
2449 if (nickserv_conf.sync_log)
2450 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, hi->cookie->data, user->info);
2451 }
2452 #ifdef WITH_LDAP
2453 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2454 int rc;
2455 if((rc = ldap_do_modify(hi->handle, NULL, hi->cookie->data)) != LDAP_SUCCESS) {
2456 /* Falied to update email in ldap, but still
2457 * updated it here.. what should we do? */
2458 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc));
2459 } else {
2460 nickserv_set_email_addr(hi, hi->cookie->data);
2461 }
2462 }
2463 else {
2464 nickserv_set_email_addr(hi, hi->cookie->data);
2465 }
2466 #else
2467 nickserv_set_email_addr(hi, hi->cookie->data);
2468 #endif
2469 if (nickserv_conf.sync_log)
2470 SyncLog("EMAILCHANGE %s %s", hi->handle, hi->cookie->data);
2471 break;
2472 default:
2473 reply("NSMSG_BAD_COOKIE_TYPE", hi->cookie->type);
2474 log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d for account %s.", hi->cookie->type, hi->handle);
2475 break;
2476 }
2477
2478 nickserv_eat_cookie(hi->cookie);
2479 reply("NSMSG_ATE_FOREIGN_COOKIE", hi->handle);
2480
2481 return 1;
2482 }
2483
2484 static NICKSERV_FUNC(cmd_resetpass)
2485 {
2486 struct handle_info *hi;
2487 char crypted[MD5_CRYPT_LENGTH];
2488 int weblink;
2489
2490 NICKSERV_MIN_PARMS(3);
2491 if(argc >= 4 && !strcmp(argv[3], "WEBLINK"))
2492 weblink = 1;
2493 else
2494 weblink = 0;
2495 if (user->handle_info) {
2496 reply("NSMSG_ALREADY_AUTHED", user->handle_info->handle);
2497 return 0;
2498 }
2499 if (IsStamped(user)) {
2500 /* Unauthenticated users might still have been stamped
2501 previously and could therefore have a hidden host;
2502 do not allow them to activate an account. */
2503 reply("NSMSG_STAMPED_RESETPASS");
2504 return 0;
2505 }
2506 if (!(hi = get_handle_info(argv[1]))) {
2507 reply("MSG_HANDLE_UNKNOWN", argv[1]);
2508 return 0;
2509 }
2510 if (!hi->email_addr) {
2511 reply("MSG_SET_EMAIL_ADDR");
2512 return 0;
2513 }
2514 cryptpass(argv[2], crypted);
2515 argv[2] = "****";
2516 nickserv_make_cookie(user, hi, PASSWORD_CHANGE, crypted, weblink);
2517 return 1;
2518 }
2519
2520 static NICKSERV_FUNC(cmd_cookie)
2521 {
2522 struct handle_info *hi;
2523 const char *cookie;
2524
2525 if ((argc == 2) && (hi = user->handle_info) && hi->cookie && (hi->cookie->type == EMAIL_CHANGE)) {
2526 cookie = argv[1];
2527 } else {
2528 NICKSERV_MIN_PARMS(3);
2529 if (!(hi = get_handle_info(argv[1]))) {
2530 reply("MSG_HANDLE_UNKNOWN", argv[1]);
2531 return 0;
2532 }
2533 cookie = argv[2];
2534 }
2535
2536 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
2537 reply("NSMSG_HANDLE_SUSPENDED");
2538 return 0;
2539 }
2540
2541 if (!hi->cookie) {
2542 reply("NSMSG_NO_COOKIE");
2543 return 0;
2544 }
2545
2546 /* Check validity of operation before comparing cookie to
2547 * prohibit guessing by authed users. */
2548 if (user->handle_info
2549 && (hi->cookie->type != EMAIL_CHANGE)
2550 && (hi->cookie->type != PASSWORD_CHANGE)) {
2551 reply("NSMSG_CANNOT_COOKIE");
2552 return 0;
2553 }
2554
2555 if (strcmp(cookie, hi->cookie->cookie)) {
2556 reply("NSMSG_BAD_COOKIE");
2557 return 0;
2558 }
2559
2560 switch (hi->cookie->type) {
2561 case ACTIVATION:
2562 #ifdef WITH_LDAP
2563 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2564 int rc;
2565 if((rc = ldap_do_modify(hi->handle, hi->cookie->data, NULL)) != LDAP_SUCCESS) {
2566 /* Falied to update email in ldap, but still
2567 * updated it here.. what should we do? */
2568 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2569 return 0;
2570 }
2571 }
2572 #endif
2573 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2574 set_user_handle_info(user, hi, 1);
2575 reply("NSMSG_HANDLE_ACTIVATED");
2576 if (nickserv_conf.sync_log)
2577 SyncLog("ACCOUNTACC %s", hi->handle);
2578 break;
2579 case PASSWORD_CHANGE:
2580 #ifdef WITH_LDAP
2581 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2582 int rc;
2583 if((rc = ldap_do_modify(hi->handle, hi->cookie->data, NULL)) != LDAP_SUCCESS) {
2584 /* Falied to update email in ldap, but still
2585 * updated it here.. what should we do? */
2586 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2587 return 0;
2588 }
2589 }
2590 #endif
2591 set_user_handle_info(user, hi, 1);
2592 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2593 reply("NSMSG_PASSWORD_CHANGED");
2594 if (nickserv_conf.sync_log)
2595 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
2596 break;
2597 case EMAIL_CHANGE:
2598 #ifdef WITH_LDAP
2599 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2600 int rc;
2601 if((rc = ldap_do_modify(hi->handle, NULL, hi->cookie->data)) != LDAP_SUCCESS) {
2602 /* Falied to update email in ldap, but still
2603 * updated it here.. what should we do? */
2604 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc));
2605 return 0;
2606 }
2607 }
2608 #endif
2609 if (!hi->email_addr && nickserv_conf.sync_log) {
2610 /*
2611 * This should only happen if an OREGISTER was sent. Require
2612 * email must be enabled! - SiRVulcaN
2613 */
2614 if (nickserv_conf.sync_log)
2615 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, hi->cookie->data, user->info);
2616 }
2617
2618 nickserv_set_email_addr(hi, hi->cookie->data);
2619 reply("NSMSG_EMAIL_CHANGED");
2620 if (nickserv_conf.sync_log)
2621 SyncLog("EMAILCHANGE %s %s", hi->handle, hi->cookie->data);
2622 break;
2623 case ALLOWAUTH:
2624 set_user_handle_info(user, hi, 1);
2625 reply("NSMSG_AUTH_SUCCESS");
2626 break;
2627 default:
2628 reply("NSMSG_BAD_COOKIE_TYPE", hi->cookie->type);
2629 log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d for account %s.", hi->cookie->type, hi->handle);
2630 break;
2631 }
2632
2633 nickserv_eat_cookie(hi->cookie);
2634
2635 process_adduser_pending(user);
2636
2637 return 1;
2638 }
2639
2640 static NICKSERV_FUNC(cmd_oregnick) {
2641 const char *nick;
2642 struct handle_info *target;
2643 struct nick_info *ni;
2644
2645 NICKSERV_MIN_PARMS(3);
2646 if (!(target = modcmd_get_handle_info(user, argv[1])))
2647 return 0;
2648 nick = argv[2];
2649 if (!is_registerable_nick(nick)) {
2650 reply("NSMSG_BAD_NICK", nick);
2651 return 0;
2652 }
2653 ni = dict_find(nickserv_nick_dict, nick, NULL);
2654 if (ni) {
2655 reply("NSMSG_NICK_EXISTS", nick);
2656 return 0;
2657 }
2658 register_nick(nick, target);
2659 reply("NSMSG_OREGNICK_SUCCESS", nick, target->handle);
2660 return 1;
2661 }
2662
2663 static NICKSERV_FUNC(cmd_regnick) {
2664 unsigned n;
2665 struct nick_info *ni;
2666
2667 if (!is_registerable_nick(user->nick)) {
2668 reply("NSMSG_BAD_NICK", user->nick);
2669 return 0;
2670 }
2671 /* count their nicks, see if it's too many */
2672 for (n=0,ni=user->handle_info->nicks; ni; n++,ni=ni->next) ;
2673 if (n >= nickserv_conf.nicks_per_handle) {
2674 reply("NSMSG_TOO_MANY_NICKS");
2675 return 0;
2676 }
2677 ni = dict_find(nickserv_nick_dict, user->nick, NULL);
2678 if (ni) {
2679 reply("NSMSG_NICK_EXISTS", user->nick);
2680 return 0;
2681 }
2682 register_nick(user->nick, user->handle_info);
2683 reply("NSMSG_REGNICK_SUCCESS", user->nick);
2684 return 1;
2685 }
2686
2687 static NICKSERV_FUNC(cmd_pass)
2688 {
2689 struct handle_info *hi;
2690 char *old_pass, *new_pass;
2691 char crypted[MD5_CRYPT_LENGTH+1];
2692 #ifdef WITH_LDAP
2693 int ldap_result;
2694 #endif
2695
2696 NICKSERV_MIN_PARMS(3);
2697 hi = user->handle_info;
2698 old_pass = argv[1];
2699 new_pass = argv[2];
2700 argv[2] = "****";
2701 if (!is_secure_password(hi->handle, new_pass, user)) return 0;
2702
2703 #ifdef WITH_LDAP
2704 if(nickserv_conf.ldap_enable) {
2705 ldap_result = ldap_check_auth(hi->handle, old_pass);
2706 if(ldap_result != LDAP_SUCCESS) {
2707 if(ldap_result == LDAP_INVALID_CREDENTIALS)
2708 reply("NSMSG_PASSWORD_INVALID");
2709 else
2710 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result));
2711 return 0;
2712 }
2713 }else
2714 #endif
2715 if (!checkpass(old_pass, hi->passwd)) {
2716 argv[1] = "BADPASS";
2717 reply("NSMSG_PASSWORD_INVALID");
2718 return 0;
2719 }
2720 cryptpass(new_pass, crypted);
2721 #ifdef WITH_LDAP
2722 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2723 int rc;
2724 if((rc = ldap_do_modify(hi->handle, crypted, NULL)) != LDAP_SUCCESS) {
2725 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2726 return 0;
2727 }
2728 }
2729 #endif
2730 //cryptpass(new_pass, hi->passwd);
2731 strcpy(hi->passwd, crypted);
2732 if (nickserv_conf.sync_log)
2733 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
2734 argv[1] = "****";
2735 reply("NSMSG_PASS_SUCCESS");
2736 return 1;
2737 }
2738
2739 static int
2740 nickserv_addmask(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, const char *mask)
2741 {
2742 unsigned int i;
2743 char *new_mask = canonicalize_hostmask(strdup(mask));
2744 for (i=0; i<hi->masks->used; i++) {
2745 if (!irccasecmp(new_mask, hi->masks->list[i])) {
2746 reply("NSMSG_ADDMASK_ALREADY", new_mask);
2747 free(new_mask);
2748 return 0;
2749 }
2750 }
2751 string_list_append(hi->masks, new_mask);
2752 reply("NSMSG_ADDMASK_SUCCESS", new_mask);
2753 return 1;
2754 }
2755
2756 static NICKSERV_FUNC(cmd_addmask)
2757 {
2758 if (argc < 2) {
2759 char *mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
2760 int res = nickserv_addmask(cmd, user, user->handle_info, mask);
2761 free(mask);
2762 return res;
2763 } else {
2764 if (!is_gline(argv[1])) {
2765 reply("NSMSG_MASK_INVALID", argv[1]);
2766 return 0;
2767 }
2768 return nickserv_addmask(cmd, user, user->handle_info, argv[1]);
2769 }
2770 }
2771
2772 static NICKSERV_FUNC(cmd_oaddmask)
2773 {
2774 struct handle_info *hi;
2775
2776 NICKSERV_MIN_PARMS(3);
2777 if (!(hi = get_victim_oper(cmd, user, argv[1])))
2778 return 0;
2779 return nickserv_addmask(cmd, user, hi, argv[2]);
2780 }
2781
2782 static int
2783 nickserv_delmask(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, const char *del_mask)
2784 {
2785 unsigned int i;
2786 for (i=0; i<hi->masks->used; i++) {
2787 if (!strcmp(del_mask, hi->masks->list[i])) {
2788 char *old_mask = hi->masks->list[i];
2789 if (hi->masks->used == 1) {
2790 reply("NSMSG_DELMASK_NOTLAST");
2791 return 0;
2792 }
2793 hi->masks->list[i] = hi->masks->list[--hi->masks->used];
2794 reply("NSMSG_DELMASK_SUCCESS", old_mask);
2795 free(old_mask);
2796 return 1;
2797 }
2798 }
2799 reply("NSMSG_DELMASK_NOT_FOUND");
2800 return 0;
2801 }
2802
2803 static NICKSERV_FUNC(cmd_delmask)
2804 {
2805 NICKSERV_MIN_PARMS(2);
2806 return nickserv_delmask(cmd, user, user->handle_info, argv[1]);
2807 }
2808
2809 static NICKSERV_FUNC(cmd_odelmask)
2810 {
2811 struct handle_info *hi;
2812 NICKSERV_MIN_PARMS(3);
2813 if (!(hi = get_victim_oper(cmd, user, argv[1])))
2814 return 0;
2815 return nickserv_delmask(cmd, user, hi, argv[2]);
2816 }
2817
2818 int
2819 nickserv_modify_handle_flags(struct userNode *user, struct userNode *bot, const char *str, unsigned long *padded, unsigned long *premoved) {
2820 unsigned int nn, add = 1, pos;
2821 unsigned long added, removed, flag;
2822
2823 for (added=removed=nn=0; str[nn]; nn++) {
2824 switch (str[nn]) {
2825 case '+': add = 1; break;
2826 case '-': add = 0; break;
2827 default:
2828 if (!(pos = handle_inverse_flags[(unsigned char)str[nn]])) {
2829 send_message(user, bot, "NSMSG_INVALID_FLAG", str[nn]);
2830 return 0;
2831 }
2832 if (user && (user->handle_info->opserv_level < flag_access_levels[pos-1])) {
2833 /* cheesy avoidance of looking up the flag name.. */
2834 send_message(user, bot, "NSMSG_FLAG_PRIVILEGED", str[nn]);
2835 return 0;
2836 }
2837 flag = 1 << (pos - 1);
2838 if (add)
2839 added |= flag, removed &= ~flag;
2840 else
2841 removed |= flag, added &= ~flag;
2842 break;
2843 }
2844 }
2845 *padded = added;
2846 *premoved = removed;
2847 return 1;
2848 }
2849
2850 static int
2851 nickserv_apply_flags(struct userNode *user, struct handle_info *hi, const char *flags)
2852 {
2853 unsigned long before, after, added, removed;
2854 struct userNode *uNode;
2855
2856 before = hi->flags & (HI_FLAG_SUPPORT_HELPER|HI_FLAG_NETWORK_HELPER);
2857 if (!nickserv_modify_handle_flags(user, nickserv, flags, &added, &removed))
2858 return 0;
2859 hi->flags = (hi->flags | added) & ~removed;
2860 after = hi->flags & (HI_FLAG_SUPPORT_HELPER|HI_FLAG_NETWORK_HELPER);
2861
2862 /* Strip helping flag if they're only a support helper and not
2863 * currently in #support. */
2864 if (HANDLE_FLAGGED(hi, HELPING) && (after == HI_FLAG_SUPPORT_HELPER)) {
2865 struct channelList *schannels;
2866 unsigned int ii;
2867 schannels = chanserv_support_channels();
2868 for (uNode = hi->users; uNode; uNode = uNode->next_authed) {
2869 for (ii = 0; ii < schannels->used; ++ii)
2870 if (GetUserMode(schannels->list[ii], uNode))
2871 break;
2872 if (ii < schannels->used)
2873 break;
2874 }
2875 if (!uNode)
2876 HANDLE_CLEAR_FLAG(hi, HELPING);
2877 }
2878
2879 if (after && !before) {
2880 /* Add user to current helper list. */
2881 for (uNode = hi->users; uNode; uNode = uNode->next_authed)
2882 userList_append(&curr_helpers, uNode);
2883 } else if (!after && before) {
2884 /* Remove user from current helper list. */
2885 for (uNode = hi->users; uNode; uNode = uNode->next_authed)
2886 userList_remove(&curr_helpers, uNode);
2887 }
2888
2889 return 1;
2890 }
2891
2892 static void
2893 set_list(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, int override)
2894 {
2895 option_func_t *opt;
2896 unsigned int i;
2897 char *set_display[] = {
2898 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2899 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2900 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2901 };
2902
2903 reply("NSMSG_SETTING_LIST");
2904 reply("NSMSG_SETTING_LIST_HEADER");
2905
2906 /* Do this so options are presented in a consistent order. */
2907 for (i = 0; i < ArrayLength(set_display); ++i)
2908 if ((opt = dict_find(nickserv_opt_dict, set_display[i], NULL)))
2909 opt(cmd, user, hi, override, 0, NULL);
2910 reply("NSMSG_SETTING_LIST_END");
2911 }
2912
2913 static NICKSERV_FUNC(cmd_set)
2914 {
2915 struct handle_info *hi;
2916 option_func_t *opt;
2917
2918 hi = user->handle_info;
2919 if (argc < 2) {
2920 set_list(cmd, user, hi, 0);
2921 return 1;
2922 }
2923 if (!(opt = dict_find(nickserv_opt_dict, argv[1], NULL))) {
2924 reply("NSMSG_INVALID_OPTION", argv[1]);
2925 return 0;
2926 }
2927 return opt(cmd, user, hi, 0, argc-1, argv+1);
2928 }
2929
2930 static NICKSERV_FUNC(cmd_oset)
2931 {
2932 struct handle_info *hi;
2933 option_func_t *opt;
2934
2935 NICKSERV_MIN_PARMS(2);
2936
2937 if (!(hi = get_victim_oper(cmd, user, argv[1])))
2938 return 0;
2939
2940 if (argc < 3) {
2941 set_list(cmd, user, hi, 0);
2942 return 1;
2943 }
2944
2945 if (!(opt = dict_find(nickserv_opt_dict, argv[2], NULL))) {
2946 reply("NSMSG_INVALID_OPTION", argv[2]);
2947 return 0;
2948 }
2949
2950 return opt(cmd, user, hi, 1, argc-2, argv+2);
2951 }
2952
2953 static OPTION_FUNC(opt_info)
2954 {
2955 const char *info;
2956 if (argc > 1) {
2957 if ((argv[1][0] == '*') && (argv[1][1] == 0)) {
2958 free(hi->infoline);
2959 hi->infoline = NULL;
2960 } else {
2961 hi->infoline = strdup(unsplit_string(argv+1, argc-1, NULL));
2962 }
2963 }
2964
2965 info = hi->infoline ? hi->infoline : user_find_message(user, "MSG_NONE");
2966 reply("NSMSG_SET_INFO", info);
2967 return 1;
2968 }
2969
2970 static OPTION_FUNC(opt_width)
2971 {
2972 if (argc > 1)
2973 hi->screen_width = strtoul(argv[1], NULL, 0);
2974
2975 if ((hi->screen_width > 0) && (hi->screen_width < MIN_LINE_SIZE))
2976 hi->screen_width = MIN_LINE_SIZE;
2977 else if (hi->screen_width > MAX_LINE_SIZE)
2978 hi->screen_width = MAX_LINE_SIZE;
2979
2980 reply("NSMSG_SET_WIDTH", hi->screen_width);
2981 return 1;
2982 }
2983
2984 static OPTION_FUNC(opt_tablewidth)
2985 {
2986 if (argc > 1)
2987 hi->table_width = strtoul(argv[1], NULL, 0);
2988
2989 if ((hi->table_width > 0) && (hi->table_width < MIN_LINE_SIZE))
2990 hi->table_width = MIN_LINE_SIZE;
2991 else if (hi->screen_width > MAX_LINE_SIZE)
2992 hi->table_width = MAX_LINE_SIZE;
2993
2994 reply("NSMSG_SET_TABLEWIDTH", hi->table_width);
2995 return 1;
2996 }
2997
2998 static OPTION_FUNC(opt_color)
2999 {
3000 if (argc > 1) {
3001 if (enabled_string(argv[1]))
3002 HANDLE_SET_FLAG(hi, MIRC_COLOR);
3003 else if (disabled_string(argv[1]))
3004 HANDLE_CLEAR_FLAG(hi, MIRC_COLOR);
3005 else {
3006 reply("MSG_INVALID_BINARY", argv[1]);
3007 return 0;
3008 }
3009 }
3010
3011 reply("NSMSG_SET_COLOR", user_find_message(user, HANDLE_FLAGGED(hi, MIRC_COLOR) ? "MSG_ON" : "MSG_OFF"));
3012 return 1;
3013 }
3014
3015 static OPTION_FUNC(opt_privmsg)
3016 {
3017 if (argc > 1) {
3018 if (enabled_string(argv[1]))
3019 HANDLE_SET_FLAG(hi, USE_PRIVMSG);
3020 else if (disabled_string(argv[1]))
3021 HANDLE_CLEAR_FLAG(hi, USE_PRIVMSG);
3022 else {
3023 reply("MSG_INVALID_BINARY", argv[1]);
3024 return 0;
3025 }
3026 }
3027
3028 reply("NSMSG_SET_PRIVMSG", user_find_message(user, HANDLE_FLAGGED(hi, USE_PRIVMSG) ? "MSG_ON" : "MSG_OFF"));
3029 return 1;
3030 }
3031
3032 static OPTION_FUNC(opt_autohide)
3033 {
3034 if (argc > 1) {
3035 if (enabled_string(argv[1]))
3036 HANDLE_SET_FLAG(hi, AUTOHIDE);
3037 else if (disabled_string(argv[1]))
3038 HANDLE_CLEAR_FLAG(hi, AUTOHIDE);
3039 else {
3040 reply("MSG_INVALID_BINARY", argv[1]);
3041 return 0;
3042 }
3043 }
3044
3045 reply("NSMSG_SET_AUTOHIDE", user_find_message(user, HANDLE_FLAGGED(hi, AUTOHIDE) ? "MSG_ON" : "MSG_OFF"));
3046 return 1;
3047 }
3048
3049 static OPTION_FUNC(opt_style)
3050 {
3051 char *style;
3052
3053 if (argc > 1) {
3054 if (!irccasecmp(argv[1], "Clean"))
3055 hi->userlist_style = HI_STYLE_CLEAN;
3056 else if (!irccasecmp(argv[1], "Advanced"))
3057 hi->userlist_style = HI_STYLE_ADVANCED;
3058 else if (!irccasecmp(argv[1], "Classic"))
3059 hi->userlist_style = HI_STYLE_CLASSIC;
3060 else /* Default to normal */
3061 hi->userlist_style = HI_STYLE_NORMAL;
3062 } /* TODO: give error if unknow style is chosen */
3063
3064 switch (hi->userlist_style) {
3065 case HI_STYLE_ADVANCED:
3066 style = "Advanced";
3067 break;
3068 case HI_STYLE_CLASSIC:
3069 style = "Classic";
3070 break;
3071 case HI_STYLE_CLEAN:
3072 style = "Clean";
3073 break;
3074 case HI_STYLE_NORMAL:
3075 default:
3076 style = "Normal";
3077 }
3078
3079 reply("NSMSG_SET_STYLE", style);
3080 return 1;
3081 }
3082
3083 static OPTION_FUNC(opt_announcements)
3084 {
3085 const char *choice;
3086
3087 if (argc > 1) {
3088 if (enabled_string(argv[1]))
3089 hi->announcements = 'y';
3090 else if (disabled_string(argv[1]))
3091 hi->announcements = 'n';
3092 else if (!strcmp(argv[1], "?") || !irccasecmp(argv[1], "default"))
3093 hi->announcements = '?';
3094 else {
3095 reply("NSMSG_INVALID_ANNOUNCE", argv[1]);
3096 return 0;
3097 }
3098 }
3099
3100 switch (hi->announcements) {
3101 case 'y': choice = user_find_message(user, "MSG_ON"); break;
3102 case 'n': choice = user_find_message(user, "MSG_OFF"); break;
3103 case '?': choice = "default"; break;
3104 default: choice = "unknown"; break;
3105 }
3106 reply("NSMSG_SET_ANNOUNCEMENTS", choice);
3107 return 1;
3108 }
3109
3110 static OPTION_FUNC(opt_password)
3111 {
3112 char crypted[MD5_CRYPT_LENGTH+1];
3113 if(argc < 2) {
3114 return 0;
3115 }
3116 if (!override) {
3117 reply("NSMSG_USE_CMD_PASS");
3118 return 0;
3119 }
3120
3121 cryptpass(argv[1], crypted);
3122 #ifdef WITH_LDAP
3123 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
3124 int rc;
3125 if((rc = ldap_do_modify(hi->handle, crypted, NULL)) != LDAP_SUCCESS) {
3126 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
3127 return 0;
3128 }
3129 }
3130 #endif
3131 strcpy(hi->passwd, crypted);
3132 if (nickserv_conf.sync_log)
3133 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
3134
3135 reply("NSMSG_SET_PASSWORD", "***");
3136 return 1;
3137 }
3138
3139 static OPTION_FUNC(opt_flags)
3140 {
3141 char flags[33];
3142 unsigned int ii, flen;
3143
3144 if (!override) {
3145 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3146 return 0;
3147 }
3148
3149 if (argc > 1)
3150 nickserv_apply_flags(user, hi, argv[1]);
3151
3152 for (ii = flen = 0; handle_flags[ii]; ii++)
3153 if (hi->flags & (1 << ii))
3154 flags[flen++] = handle_flags[ii];
3155 flags[flen] = '\0';
3156 if (hi->flags)
3157 reply("NSMSG_SET_FLAGS", flags);
3158 else
3159 reply("NSMSG_SET_FLAGS", user_find_message(user, "MSG_NONE"));
3160 return 1;
3161 }
3162
3163 static OPTION_FUNC(opt_email)
3164 {
3165 if (argc > 1) {
3166 const char *str;
3167 if (!valid_email(argv[1])) {
3168 reply("NSMSG_BAD_EMAIL_ADDR");
3169 return 0;
3170 }
3171 if ((str = sendmail_prohibited_address(argv[1]))) {
3172 reply("NSMSG_EMAIL_PROHIBITED", argv[1], str);
3173 return 0;
3174 }
3175 if (hi->email_addr && !irccasecmp(hi->email_addr, argv[1]))
3176 reply("NSMSG_EMAIL_SAME");
3177 else if (!override)
3178 nickserv_make_cookie(user, hi, EMAIL_CHANGE, argv[1], 0);
3179 else {
3180 #ifdef WITH_LDAP
3181 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
3182 int rc;
3183 if((rc = ldap_do_modify(hi->handle, NULL, argv[1])) != LDAP_SUCCESS) {
3184 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
3185 return 0;
3186 }
3187 }
3188 #endif
3189 nickserv_set_email_addr(hi, argv[1]);
3190 if (hi->cookie)
3191 nickserv_eat_cookie(hi->cookie);
3192 reply("NSMSG_SET_EMAIL", visible_email_addr(user, hi));
3193 }
3194 } else
3195 reply("NSMSG_SET_EMAIL", visible_email_addr(user, hi));
3196 return 1;
3197 }
3198
3199 static OPTION_FUNC(opt_maxlogins)
3200 {
3201 unsigned char maxlogins;
3202 if (argc > 1) {
3203 maxlogins = strtoul(argv[1], NULL, 0);
3204 if ((maxlogins > nickserv_conf.hard_maxlogins) && !override) {
3205 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf.hard_maxlogins);
3206 return 0;
3207 }
3208 hi->maxlogins = maxlogins;
3209 }
3210 maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
3211 reply("NSMSG_SET_MAXLOGINS", maxlogins);
3212 return 1;
3213 }
3214
3215 static OPTION_FUNC(opt_advanced)
3216 {
3217 if (argc > 1) {
3218 if (enabled_string(argv[1]))
3219 HANDLE_SET_FLAG(hi, ADVANCED);
3220 else if (disabled_string(argv[1]))
3221 HANDLE_CLEAR_FLAG(hi, ADVANCED);
3222 else {
3223 reply("MSG_INVALID_BINARY", argv[1]);
3224 return 0;
3225 }
3226 }
3227
3228 reply("NSMSG_SET_ADVANCED", user_find_message(user, HANDLE_FLAGGED(hi, ADVANCED) ? "MSG_ON" : "MSG_OFF"));
3229 return 1;
3230 }
3231
3232 static OPTION_FUNC(opt_language)
3233 {
3234 struct language *lang;
3235 if (argc > 1) {
3236 lang = language_find(argv[1]);
3237 if (irccasecmp(lang->name, argv[1]))
3238 reply("NSMSG_LANGUAGE_NOT_FOUND", argv[1], lang->name);
3239 hi->language = lang;
3240 }
3241 reply("NSMSG_SET_LANGUAGE", hi->language->name);
3242 return 1;
3243 }
3244
3245 /* Called from opserv from cmd_access */
3246 int
3247 oper_try_set_access(struct userNode *user, struct userNode *bot, struct handle_info *target, unsigned int new_level) {
3248 if (!oper_has_access(user, bot, nickserv_conf.modoper_level, 0))
3249 return 0;
3250 if ((user->handle_info->opserv_level < target->opserv_level)
3251 || ((user->handle_info->opserv_level == target->opserv_level)
3252 && (user->handle_info->opserv_level < 1000))) {
3253 send_message(user, bot, "MSG_USER_OUTRANKED", target->handle);
3254 return 0;
3255 }
3256 if ((user->handle_info->opserv_level < new_level)
3257 || ((user->handle_info->opserv_level == new_level)
3258 && (user->handle_info->opserv_level < 1000))) {
3259 send_message(user, bot, "NSMSG_OPSERV_LEVEL_BAD");
3260 return 0;
3261 }
3262 if (user->handle_info == target) {
3263 send_message(user, bot, "MSG_STUPID_ACCESS_CHANGE");
3264 return 0;
3265 }
3266 #ifdef WITH_LDAP
3267 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_oper_group_dn && nickserv_conf.ldap_admin_dn) {
3268 int rc;
3269 if(new_level > nickserv_conf.ldap_oper_group_level)
3270 rc = ldap_add2group(target->handle, nickserv_conf.ldap_oper_group_dn);
3271 else
3272 rc = ldap_delfromgroup(target->handle, nickserv_conf.ldap_oper_group_dn);
3273 if(rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS && rc != LDAP_NO_SUCH_ATTRIBUTE) {
3274 send_message(user, bot, "NSMSG_LDAP_FAIL", ldap_err2string(rc));
3275 return 0;
3276 }
3277 }
3278 #endif
3279 if (target->opserv_level == new_level)
3280 return 0;
3281 log_module(NS_LOG, LOG_INFO, "Account %s setting oper level for account %s to %d (from %d).",
3282 user->handle_info->handle, target->handle, new_level, target->opserv_level);
3283 target->opserv_level = new_level;
3284 return 1;
3285 }
3286
3287 static OPTION_FUNC(opt_level)
3288 {
3289 int res;
3290
3291 if (!override) {
3292 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3293 return 0;
3294 }
3295
3296 res = (argc > 1) ? oper_try_set_access(user, nickserv, hi, strtoul(argv[1], NULL, 0)) : 0;
3297 reply("NSMSG_SET_LEVEL", hi->opserv_level);
3298 return res;
3299 }
3300
3301 static OPTION_FUNC(opt_epithet)
3302 {
3303 if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_epithet_level, 0)) {
3304 char *epithet;
3305 struct userNode *target, *next_un;
3306
3307 if (!override) {
3308 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3309 return 0;
3310 }
3311
3312 epithet = unsplit_string(argv+1, argc-1, NULL);
3313
3314 if (hi->epithet)
3315 free(hi->epithet);
3316 if ((epithet[0] == '*') && !epithet[1])
3317 hi->epithet = NULL;
3318 else
3319 hi->epithet = strdup(epithet);
3320
3321 for (target = hi->users; target; target = next_un) {
3322 irc_swhois(nickserv, target, hi->epithet);
3323
3324 next_un = target->next_authed;
3325 }
3326 }
3327
3328 if (hi->epithet)
3329 reply("NSMSG_SET_EPITHET", hi->epithet);
3330 else
3331 reply("NSMSG_SET_EPITHET", user_find_message(user, "MSG_NONE"));
3332 return 1;
3333 }
3334
3335 static OPTION_FUNC(opt_title)
3336 {
3337 char *title;
3338 const char *none;
3339 char *sptr;
3340
3341 if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_title_level, 0)) {
3342 if (!override) {
3343 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3344 return 0;
3345 }
3346
3347 title = argv[1];
3348 if(!strcmp(title, "*")) {
3349 free(hi->fakehost);
3350 hi->fakehost = NULL;
3351 }
3352 else {
3353 if (strchr(title, '.')) {
3354 reply("NSMSG_TITLE_INVALID");
3355 return 0;
3356 }
3357 /* Alphanumeric titles only. */
3358 for(sptr = title; *sptr; sptr++) {
3359 if(!isalnum(*sptr) && *sptr != '-') {
3360 reply("NSMSG_TITLE_INVALID");
3361 return 0;
3362 }
3363 }
3364 if ((strlen(user->handle_info->handle) + strlen(title) +
3365 strlen(nickserv_conf.titlehost_suffix) + 2) > HOSTLEN) {
3366 reply("NSMSG_TITLE_TRUNCATED");
3367 return 0;
3368 }
3369 free(hi->fakehost);
3370 hi->fakehost = malloc(strlen(title)+2);
3371 hi->fakehost[0] = '.';
3372 strcpy(hi->fakehost+1, title);
3373 }
3374 apply_fakehost(hi);
3375 } else if (hi->fakehost && (hi->fakehost[0] == '.'))
3376 title = hi->fakehost + 1;
3377 else {
3378 /* If theres no title set then the default title will therefore
3379 be the first part of hidden_host in x3.conf, so for
3380 consistency with opt_fakehost we will print this here.
3381 This isnt actually used in P10, its just handled to keep from crashing... */
3382 char *hs, *hidden_suffix, *rest;
3383
3384 hs = conf_get_data("server/hidden_host", RECDB_QSTRING);
3385 hidden_suffix = strdup(hs);
3386
3387 /* Yes we do this twice */
3388 if((rest = strchr(hidden_suffix, '.')))
3389 {
3390 *rest = '\0';
3391 title = hidden_suffix;
3392 }
3393 else
3394 {
3395 /* A lame default if someone configured hidden_host to something lame */
3396 title = strdup("users");
3397 free(hidden_suffix);
3398 }
3399
3400 }
3401
3402 if (!title)
3403 none = user_find_message(user, "MSG_NONE");
3404 send_message(user, nickserv, "NSMSG_SET_TITLE", title ? title : none);
3405 return 1;
3406 }
3407
3408 int
3409 check_vhost(char *vhost, struct userNode *user, struct svccmd *cmd)
3410 {
3411 unsigned int y;
3412
3413 // check for a dot in the vhost
3414 if(strchr(vhost, '.') == NULL) {
3415 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost);
3416 return 0;
3417 }
3418
3419 // check for a @ in the vhost
3420 if(strchr(vhost, '@') != NULL) {
3421 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost);
3422 return 0;
3423 }
3424
3425 // check for denied words, inspired by monk at paki.sex
3426 for(y = 0; y < nickserv_conf.denied_fakehost_words->used; y++) {
3427 if(strstr(vhost, nickserv_conf.denied_fakehost_words->list[y]) != NULL) {
3428 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost, nickserv_conf.denied_fakehost_words->list[y]);
3429 return 0;
3430 }
3431 }
3432
3433 // check for ircu's HOSTLEN length.
3434 if(strlen(vhost) >= HOSTLEN) {
3435 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost);
3436 return 0;
3437 }
3438
3439 /* This can be handled by the regex now if desired.
3440 if (vhost[strspn(vhost, "0123456789.")]) {
3441 hostname = vhost + strlen(vhost);
3442 for (depth = 1; depth && (hostname > vhost); depth--) {
3443 hostname--;
3444 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3445 }
3446
3447 if (*hostname == '.') hostname++; * advance past last dot we saw *
3448 if(strlen(hostname) > 4) {
3449 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3450 return 0;
3451 }
3452 }
3453 */
3454 /* test either regex or as valid handle */
3455 if (nickserv_conf.valid_fakehost_regex_set) {
3456 int err = regexec(&nickserv_conf.valid_fakehost_regex, vhost, 0, 0, 0);
3457 if (err) {
3458 char buff[256];
3459 buff[regerror(err, &nickserv_conf.valid_fakehost_regex, buff, sizeof(buff))] = 0;
3460 log_module(NS_LOG, LOG_INFO, "regexec error: %s (%d)", buff, err);
3461 }
3462 if(err == REG_NOMATCH) {
3463 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost);
3464 return 0;
3465 }
3466 }
3467
3468
3469 return 1;
3470 }
3471
3472 static OPTION_FUNC(opt_fakehost)
3473 {
3474 const char *fake;
3475
3476 if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_fakehost_level, 0)) {
3477 if (!override) {
3478 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3479 return 0;
3480 }
3481
3482 fake = argv[1];
3483 if ((strlen(fake) > HOSTLEN) || (fake[0] == '.')) {
3484 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN);
3485 return 0;
3486 }
3487 if (!strcmp(fake, "*")) {
3488 if(hi->fakehost) {
3489 free(hi->fakehost);
3490 hi->fakehost = NULL;
3491 }
3492 }
3493 else if (!check_vhost(argv[1], user, cmd)) {
3494 /* check_vhost takes care of error reply */
3495 return 0;
3496 }
3497 else {
3498 if(hi->fakehost)
3499 free(hi->fakehost);
3500 hi->fakehost = strdup(fake);
3501 }
3502 apply_fakehost(hi);
3503 fake = hi->fakehost;
3504 } else
3505 fake = generate_fakehost(hi);
3506
3507 /* Tell them we set the host */
3508 if (!fake)
3509 fake = user_find_message(user, "MSG_NONE");
3510 reply("NSMSG_SET_FAKEHOST", fake);
3511 return 1;
3512 }
3513
3514 static OPTION_FUNC(opt_note)
3515 {
3516 if (!override) {
3517 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3518 return 0;
3519 }
3520
3521 if (argc > 1) {
3522 char *text = unsplit_string(argv + 1, argc - 1, NULL);
3523
3524 if (hi->note)
3525 free(hi->note);
3526
3527 if ((text[0] == '*') && !text[1])
3528 hi->note = NULL;
3529 else {
3530 if (!(hi->note = nickserv_add_note(user->handle_info->handle, now, text)))
3531 hi->note = NULL;
3532 }
3533 }
3534
3535 reply("NSMSG_SET_NOTE", hi->note ? hi->note->note : user_find_message(user, "MSG_NONE"));
3536 return 1;
3537 }
3538
3539 static NICKSERV_FUNC(cmd_reclaim)
3540 {
3541 struct handle_info *hi;
3542 struct nick_info *ni;
3543 struct userNode *victim;
3544
3545 NICKSERV_MIN_PARMS(2);
3546 hi = user->handle_info;
3547 ni = dict_find(nickserv_nick_dict, argv[1], 0);
3548 if (!ni) {
3549 reply("NSMSG_UNKNOWN_NICK", argv[1]);
3550 return 0;
3551 }
3552 if (ni->owner != user->handle_info) {
3553 reply("NSMSG_NOT_YOUR_NICK", ni->nick);
3554 return 0;
3555 }
3556 victim = GetUserH(ni->nick);
3557 if (!victim) {
3558 reply("MSG_NICK_UNKNOWN", ni->nick);
3559 return 0;
3560 }
3561 if (victim == user) {
3562 reply("NSMSG_NICK_USER_YOU");
3563 return 0;
3564 }
3565 nickserv_reclaim(victim, ni, nickserv_conf.reclaim_action);
3566 switch (nickserv_conf.reclaim_action) {
3567 case RECLAIM_NONE: reply("NSMSG_RECLAIMED_NONE"); break;
3568 case RECLAIM_WARN: reply("NSMSG_RECLAIMED_WARN", victim->nick); break;
3569 case RECLAIM_SVSNICK: reply("NSMSG_RECLAIMED_SVSNICK", victim->nick); break;
3570 case RECLAIM_KILL: reply("NSMSG_RECLAIMED_KILL", victim->nick); break;
3571 }
3572 return 1;
3573 }
3574
3575 static NICKSERV_FUNC(cmd_unregnick)
3576 {
3577 const char *nick;
3578 struct handle_info *hi;
3579 struct nick_info *ni;
3580
3581 hi = user->handle_info;
3582 nick = (argc < 2) ? user->nick : (const char*)argv[1];
3583 ni = dict_find(nickserv_nick_dict, nick, NULL);
3584 if (!ni) {
3585 reply("NSMSG_UNKNOWN_NICK", nick);
3586 return 0;
3587 }
3588 if (hi != ni->owner) {
3589 reply("NSMSG_NOT_YOUR_NICK", nick);
3590 return 0;
3591 }
3592 reply("NSMSG_UNREGNICK_SUCCESS", ni->nick);
3593 delete_nick(ni);
3594 return 1;
3595 }
3596
3597 static NICKSERV_FUNC(cmd_ounregnick)
3598 {
3599 struct nick_info *ni;
3600
3601 NICKSERV_MIN_PARMS(2);
3602 if (!(ni = get_nick_info(argv[1]))) {
3603 reply("NSMSG_NICK_NOT_REGISTERED", argv[1]);
3604 return 0;
3605 }
3606 if (ni->owner->opserv_level >= user->handle_info->opserv_level) {
3607 reply("MSG_USER_OUTRANKED", ni->nick);
3608 return 0;
3609 }
3610 reply("NSMSG_UNREGNICK_SUCCESS", ni->nick);
3611 delete_nick(ni);
3612 return 1;
3613 }
3614
3615 static NICKSERV_FUNC(cmd_unregister)
3616 {
3617 struct handle_info *hi;
3618 char *passwd;
3619
3620 NICKSERV_MIN_PARMS(2);
3621 hi = user->handle_info;
3622 passwd = argv[1];
3623 argv[1] = "****";
3624 if (checkpass(passwd, hi->passwd)) {
3625 if(nickserv_unregister_handle(hi, user, cmd->parent->bot))
3626 return 1;
3627 else
3628 return 0;
3629 } else {
3630 log_module(NS_LOG, LOG_INFO, "Account '%s' tried to unregister with the wrong password.", hi->handle);
3631 reply("NSMSG_PASSWORD_INVALID");
3632 return 0;
3633 }
3634 }
3635
3636 static NICKSERV_FUNC(cmd_ounregister)
3637 {
3638 struct handle_info *hi;
3639
3640 NICKSERV_MIN_PARMS(2);
3641 if (!(hi = get_victim_oper(cmd, user, argv[1])))
3642 return 0;
3643 if(nickserv_unregister_handle(hi, user, cmd->parent->bot))
3644 return 1;
3645 else
3646 return 0;
3647 }
3648
3649 static NICKSERV_FUNC(cmd_status)
3650 {
3651 if (nickserv_conf.disable_nicks) {
3652 reply("NSMSG_GLOBAL_STATS_NONICK",
3653 dict_size(nickserv_handle_dict));
3654 } else {
3655 if (user->handle_info) {
3656 int cnt=0;
3657 struct nick_info *ni;
3658 for (ni=user->handle_info->nicks; ni; ni=ni->next) cnt++;
3659 reply("NSMSG_HANDLE_STATS", cnt);
3660 } else {
3661 reply("NSMSG_HANDLE_NONE");
3662 }
3663 reply("NSMSG_GLOBAL_STATS",
3664 dict_size(nickserv_handle_dict),
3665 dict_size(nickserv_nick_dict));
3666 }
3667 return 1;
3668 }
3669
3670 static NICKSERV_FUNC(cmd_ghost)
3671 {
3672 struct userNode *target;
3673 char reason[MAXLEN];
3674
3675 NICKSERV_MIN_PARMS(2);
3676 if (!(target = GetUserH(argv[1]))) {
3677 reply("MSG_NICK_UNKNOWN", argv[1]);
3678 return 0;
3679 }
3680 if (target == user) {
3681 reply("NSMSG_CANNOT_GHOST_SELF");
3682 return 0;
3683 }
3684 if (!target->handle_info || (target->handle_info != user->handle_info)) {
3685 reply("NSMSG_CANNOT_GHOST_USER", target->nick);
3686 return 0;
3687 }
3688 snprintf(reason, sizeof(reason), "Ghost kill on account %s (requested by %s).", target->handle_info->handle, user->nick);
3689 DelUser(target, nickserv, 1, reason);
3690 reply("NSMSG_GHOST_KILLED", argv[1]);
3691 return 1;
3692 }
3693
3694 static NICKSERV_FUNC(cmd_vacation)
3695 {
3696 HANDLE_SET_FLAG(user->handle_info, FROZEN);
3697 reply("NSMSG_ON_VACATION");
3698 return 1;
3699 }
3700
3701 static int
3702 nickserv_saxdb_write(struct saxdb_context *ctx) {
3703 dict_iterator_t it;
3704 struct handle_info *hi;
3705 char flags[33];
3706
3707 for (it = dict_first(nickserv_handle_dict); it; it = iter_next(it)) {
3708 hi = iter_data(it);
3709 saxdb_start_record(ctx, iter_key(it), 0);
3710 if (hi->announcements != '?') {
3711 flags[0] = hi->announcements;
3712 flags[1] = 0;
3713 saxdb_write_string(ctx, KEY_ANNOUNCEMENTS, flags);
3714 }
3715 if (hi->cookie) {
3716 struct handle_cookie *cookie = hi->cookie;
3717 char *type;
3718
3719 switch (cookie->type) {
3720 case ACTIVATION: type = KEY_ACTIVATION; break;
3721 case PASSWORD_CHANGE: type = KEY_PASSWORD_CHANGE; break;
3722 case EMAIL_CHANGE: type = KEY_EMAIL_CHANGE; break;
3723 case ALLOWAUTH: type = KEY_ALLOWAUTH; break;
3724 default: type = NULL; break;
3725 }
3726 if (type) {
3727 saxdb_start_record(ctx, KEY_COOKIE, 0);
3728 saxdb_write_string(ctx, KEY_COOKIE_TYPE, type);
3729 saxdb_write_int(ctx, KEY_COOKIE_EXPIRES, cookie->expires);
3730 if (cookie->data)
3731 saxdb_write_string(ctx, KEY_COOKIE_DATA, cookie->data);
3732 saxdb_write_string(ctx, KEY_COOKIE, cookie->cookie);
3733 saxdb_end_record(ctx);
3734 }
3735 }
3736 if (hi->email_addr)
3737 saxdb_write_string(ctx, KEY_EMAIL_ADDR, hi->email_addr);
3738 if (hi->epithet)
3739 saxdb_write_string(ctx, KEY_EPITHET, hi->epithet);
3740 if (hi->note) {
3741 saxdb_start_record(ctx, KEY_NOTE_NOTE, 0);
3742 saxdb_write_string(ctx, KEY_NOTE_SETTER, hi->note->setter);
3743 saxdb_write_int(ctx, KEY_NOTE_DATE, hi->note->date);
3744 saxdb_write_string(ctx, KEY_NOTE_NOTE, hi->note->note);
3745 saxdb_end_record(ctx);
3746 }
3747
3748 if (hi->fakehost)
3749 saxdb_write_string(ctx, KEY_FAKEHOST, hi->fakehost);
3750 if (hi->flags) {
3751 int ii, flen;
3752
3753 for (ii=flen=0; handle_flags[ii]; ++ii)
3754 if (hi->flags & (1 << ii))
3755 flags[flen++] = handle_flags[ii];
3756 flags[flen] = 0;
3757 saxdb_write_string(ctx, KEY_FLAGS, flags);
3758 }
3759 if (hi->infoline)
3760 saxdb_write_string(ctx, KEY_INFO, hi->infoline);
3761 if (hi->last_quit_host[0])
3762 saxdb_write_string(ctx, KEY_LAST_QUIT_HOST, hi->last_quit_host);
3763 saxdb_write_int(ctx, KEY_LAST_SEEN, hi->lastseen);
3764 if (hi->masks->used)
3765 saxdb_write_string_list(ctx, KEY_MASKS, hi->masks);
3766 if (hi->ignores->used)
3767 saxdb_write_string_list(ctx, KEY_IGNORES, hi->ignores);
3768 if (hi->maxlogins)
3769 saxdb_write_int(ctx, KEY_MAXLOGINS, hi->maxlogins);
3770 if (hi->nicks) {
3771 struct string_list *slist;
3772 struct nick_info *ni;
3773
3774 slist = alloc_string_list(nickserv_conf.nicks_per_handle);
3775 for (ni = hi->nicks; ni; ni = ni->next) string_list_append(slist, ni->nick);
3776 saxdb_write_string_list(ctx, KEY_NICKS, slist);
3777 free(slist->list);
3778 free(slist);
3779 }
3780 if (hi->opserv_level)
3781 saxdb_write_int(ctx, KEY_OPSERV_LEVEL, hi->opserv_level);
3782 if (hi->language != lang_C)
3783 saxdb_write_string(ctx, KEY_LANGUAGE, hi->language->name);
3784 saxdb_write_string(ctx, KEY_PASSWD, hi->passwd);
3785 saxdb_write_int(ctx, KEY_REGISTER_ON, hi->registered);
3786 if (hi->screen_width)
3787 saxdb_write_int(ctx, KEY_SCREEN_WIDTH, hi->screen_width);
3788 if (hi->table_width)
3789 saxdb_write_int(ctx, KEY_TABLE_WIDTH, hi->table_width);
3790 flags[0] = hi->userlist_style;
3791 flags[1] = 0;
3792 saxdb_write_string(ctx, KEY_USERLIST_STYLE, flags);
3793 saxdb_end_record(ctx);
3794 }
3795
3796 return 0;
3797 }
3798
3799 static handle_merge_func_t *handle_merge_func_list;
3800 static unsigned int handle_merge_func_size = 0, handle_merge_func_used = 0;
3801
3802 void
3803 reg_handle_merge_func(handle_merge_func_t func)
3804 {
3805 if (handle_merge_func_used == handle_merge_func_size) {
3806 if (handle_merge_func_size) {
3807 handle_merge_func_size <<= 1;
3808 handle_merge_func_list = realloc(handle_merge_func_list, handle_merge_func_size*sizeof(handle_merge_func_t));
3809 } else {
3810 handle_merge_func_size = 8;
3811 handle_merge_func_list = malloc(handle_merge_func_size*sizeof(handle_merge_func_t));
3812 }
3813 }
3814 handle_merge_func_list[handle_merge_func_used++] = func;
3815 }
3816
3817 static NICKSERV_FUNC(cmd_merge)
3818 {
3819 struct handle_info *hi_from, *hi_to;
3820 struct userNode *last_user;
3821 struct userData *cList, *cListNext;
3822 unsigned int ii, jj, n;
3823
3824 NICKSERV_MIN_PARMS(3);
3825
3826 if (!(hi_from = get_victim_oper(cmd, user, argv[1])))
3827 return 0;
3828 if (!(hi_to = get_victim_oper(cmd, user, argv[2])))
3829 return 0;
3830 if (hi_to == hi_from) {
3831 reply("NSMSG_CANNOT_MERGE_SELF", hi_to->handle);
3832 return 0;
3833 }
3834
3835 for (n=0; n<handle_merge_func_used; n++)
3836 handle_merge_func_list[n](user, hi_to, hi_from);
3837
3838 /* Append "from" handle's nicks to "to" handle's nick list. */
3839 if (hi_to->nicks) {
3840 struct nick_info *last_ni;
3841 for (last_ni=hi_to->nicks; last_ni->next; last_ni=last_ni->next) ;
3842 last_ni->next = hi_from->nicks;
3843 }
3844 while (hi_from->nicks) {
3845 hi_from->nicks->owner = hi_to;
3846 hi_from->nicks = hi_from->nicks->next;
3847 }
3848
3849 /* Merge the hostmasks. */
3850 for (ii=0; ii<hi_from->masks->used; ii++) {
3851 char *mask = hi_from->masks->list[ii];
3852 for (jj=0; jj<hi_to->masks->used; jj++)
3853 if (match_ircglobs(hi_to->masks->list[jj], mask))
3854 break;
3855 if (jj==hi_to->masks->used) /* Nothing from the "to" handle covered this mask, so add it. */
3856 string_list_append(hi_to->masks, strdup(mask));
3857 }
3858
3859 /* Merge the ignores. */
3860 for (ii=0; ii<hi_from->ignores->used; ii++) {
3861 char *ignore = hi_from->ignores->list[ii];
3862 for (jj=0; jj<hi_to->ignores->used; jj++)
3863 if (match_ircglobs(hi_to->ignores->list[jj], ignore))
3864 break;
3865 if (jj==hi_to->ignores->used) /* Nothing from the "to" handle covered this mask, so add it. */
3866 string_list_append(hi_to->ignores, strdup(ignore));
3867 }
3868
3869 /* Merge the lists of authed users. */
3870 if (hi_to->users) {
3871 for (last_user=hi_to->users; last_user->next_authed; last_user=last_user->next_authed) ;
3872 last_user->next_authed = hi_from->users;
3873 } else {
3874 hi_to->users = hi_from->users;
3875 }
3876 /* Repoint the old "from" handle's users. */
3877 for (last_user=hi_from->users; last_user; last_user=last_user->next_authed) {
3878 last_user->handle_info = hi_to;
3879 }
3880 hi_from->users = NULL;
3881
3882 /* Merge channel userlists. */
3883 for (cList=hi_from->channels; cList; cList=cListNext) {
3884 struct userData *cList2;
3885 cListNext = cList->u_next;
3886 for (cList2=hi_to->channels; cList2; cList2=cList2->u_next)
3887 if (cList->channel == cList2->channel)
3888 break;
3889 if (cList2 && (cList2->access >= cList->access)) {
3890 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);
3891 /* keep cList2 in hi_to; remove cList from hi_from */
3892 del_channel_user(cList, 1);
3893 } else {
3894 if (cList2) {
3895 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);
3896 /* remove the lower-ranking cList2 from hi_to */
3897 del_channel_user(cList2, 1);
3898 } else {
3899 log_module(NS_LOG, LOG_INFO, "Merge: %s had no access in %s", hi_to->handle, cList->channel->channel->name);
3900 }
3901 /* cList needs to be moved from hi_from to hi_to */
3902 cList->handle = hi_to;
3903 /* Remove from linked list for hi_from */
3904 assert(!cList->u_prev);
3905 hi_from->channels = cList->u_next;
3906 if (cList->u_next)
3907 cList->u_next->u_prev = cList->u_prev;
3908 /* Add to linked list for hi_to */
3909 cList->u_prev = NULL;
3910 cList->u_next = hi_to->channels;
3911 if (hi_to->channels)
3912 hi_to->channels->u_prev = cList;
3913 hi_to->channels = cList;
3914 }
3915 }
3916
3917 /* Do they get an OpServ level promotion? */
3918 if (hi_from->opserv_level > hi_to->opserv_level)
3919 hi_to->opserv_level = hi_from->opserv_level;
3920
3921 /* What about last seen time? */
3922 if (hi_from->lastseen > hi_to->lastseen)
3923 hi_to->lastseen = hi_from->lastseen;
3924
3925 /* Does a fakehost carry over? (This intentionally doesn't set it
3926 * for users previously attached to hi_to. They'll just have to
3927 * reconnect.)
3928 */
3929 if (hi_from->fakehost && !hi_to->fakehost)
3930 hi_to->fakehost = strdup(hi_from->fakehost);
3931
3932 /* Notify of success. */
3933 reply("NSMSG_HANDLES_MERGED", hi_from->handle, hi_to->handle);
3934 global_message_args(MESSAGE_RECIPIENT_OPERS, "NSMSG_ACCOUNT_MERGED", user->nick,
3935 user->handle_info->handle, hi_from->handle, hi_to->handle);
3936
3937 /* Unregister the "from" handle. */
3938 nickserv_unregister_handle(hi_from, NULL, cmd->parent->bot);
3939 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
3940 * the process isn't completed.
3941 */
3942
3943 return 1;
3944 }
3945
3946 struct nickserv_discrim {
3947 unsigned int limit, min_level, max_level;
3948 unsigned long flags_on, flags_off;
3949 time_t min_registered, max_registered;
3950 time_t lastseen;
3951 enum { SUBSET, EXACT, SUPERSET, LASTQUIT } hostmask_type;
3952 const char *nickmask;
3953 const char *hostmask;
3954 const char *handlemask;
3955 const char *emailmask;
3956 #ifdef WITH_LDAP
3957 unsigned int inldap;
3958 #endif
3959 };
3960
3961 typedef void (*discrim_search_func)(struct userNode *source, struct handle_info *hi);
3962
3963 struct discrim_apply_info {
3964 struct nickserv_discrim *discrim;
3965 discrim_search_func func;
3966 struct userNode *source;
3967 unsigned int matched;
3968 };
3969
3970 static struct nickserv_discrim *
3971 nickserv_discrim_create(struct svccmd *cmd, struct userNode *user, unsigned int argc, char *argv[])
3972 {
3973 unsigned int i;
3974 struct nickserv_discrim *discrim;
3975
3976 discrim = malloc(sizeof(*discrim));
3977 memset(discrim, 0, sizeof(*discrim));
3978 discrim->min_level = 0;
3979 discrim->max_level = ~0;
3980 discrim->limit = 50;
3981 discrim->min_registered = 0;
3982 discrim->max_registered = INT_MAX;
3983 discrim->lastseen = now;
3984 #ifdef WITH_LDAP
3985 discrim->inldap = 2;
3986 #endif
3987
3988 for (i=0; i<argc; i++) {
3989 if (i == argc - 1) {
3990 reply("MSG_MISSING_PARAMS", argv[i]);
3991 goto fail;
3992 }
3993 if (!irccasecmp(argv[i], "limit")) {
3994 discrim->limit = strtoul(argv[++i], NULL, 0);
3995 } else if (!irccasecmp(argv[i], "flags")) {
3996 nickserv_modify_handle_flags(user, nickserv, argv[++i], &discrim->flags_on, &discrim->flags_off);
3997 } else if (!irccasecmp(argv[i], "registered")) {
3998 const char *cmp = argv[++i];
3999 if (cmp[0] == '<') {
4000 if (cmp[1] == '=') {
4001 discrim->min_registered = now - ParseInterval(cmp+2);
4002 } else {
4003 discrim->min_registered = now - ParseInterval(cmp+1) + 1;
4004 }
4005 } else if (cmp[0] == '=') {
4006 discrim->min_registered = discrim->max_registered = now - ParseInterval(cmp+1);
4007 } else if (cmp[0] == '>') {
4008 if (cmp[1] == '=') {
4009 discrim->max_registered = now - ParseInterval(cmp+2);
4010 } else {
4011 discrim->max_registered = now - ParseInterval(cmp+1) - 1;
4012 }
4013 } else {
4014 reply("MSG_INVALID_CRITERIA", cmp);
4015 }
4016 } else if (!irccasecmp(argv[i], "seen")) {
4017 discrim->lastseen = now - ParseInterval(argv[++i]);
4018 } else if (!nickserv_conf.disable_nicks && !irccasecmp(argv[i], "nickmask")) {
4019 discrim->nickmask = argv[++i];
4020 } else if (!irccasecmp(argv[i], "hostmask")) {
4021 i++;
4022 if (!irccasecmp(argv[i], "exact")) {
4023 if (i == argc - 1) {
4024 reply("MSG_MISSING_PARAMS", argv[i]);
4025 goto fail;
4026 }
4027 discrim->hostmask_type = EXACT;
4028 } else if (!irccasecmp(argv[i], "subset")) {
4029 if (i == argc - 1) {
4030 reply("MSG_MISSING_PARAMS", argv[i]);
4031 goto fail;
4032 }
4033 discrim->hostmask_type = SUBSET;
4034 } else if (!irccasecmp(argv[i], "superset")) {
4035 if (i == argc - 1) {
4036 reply("MSG_MISSING_PARAMS", argv[i]);
4037 goto fail;
4038 }
4039 discrim->hostmask_type = SUPERSET;
4040 } else if (!irccasecmp(argv[i], "lastquit") || !irccasecmp(argv[i], "lastauth")) {
4041 if (i == argc - 1) {
4042 reply("MSG_MISSING_PARAMS", argv[i]);
4043 goto fail;
4044 }
4045 discrim->hostmask_type = LASTQUIT;
4046 } else {
4047 i--;
4048 discrim->hostmask_type = SUPERSET;
4049 }
4050 discrim->hostmask = argv[++i];
4051 } else if (!irccasecmp(argv[i], "handlemask") || !irccasecmp(argv[i], "accountmask") || !irccasecmp(argv[i], "account")) {
4052 if (!irccasecmp(argv[++i], "*")) {
4053 discrim->handlemask = 0;
4054 } else {
4055 discrim->handlemask = argv[i];
4056 }
4057 } else if (!irccasecmp(argv[i], "email")) {
4058 if (user->handle_info->opserv_level < nickserv_conf.email_search_level) {
4059 reply("MSG_NO_SEARCH_ACCESS", "email");
4060 goto fail;
4061 } else if (!irccasecmp(argv[++i], "*")) {
4062 discrim->emailmask = 0;
4063 } else {
4064 discrim->emailmask = argv[i];
4065 }
4066 } else if (!irccasecmp(argv[i], "access")) {
4067 const char *cmp = argv[++i];
4068 if (cmp[0] == '<') {
4069 if (discrim->min_level == 0) discrim->min_level = 1;
4070 if (cmp[1] == '=') {
4071 discrim->max_level = strtoul(cmp+2, NULL, 0);
4072 } else {
4073 discrim->max_level = strtoul(cmp+1, NULL, 0) - 1;
4074 }
4075 } else if (cmp[0] == '=') {
4076 discrim->min_level = discrim->max_level = strtoul(cmp+1, NULL, 0);
4077 } else if (cmp[0] == '>') {
4078 if (cmp[1] == '=') {
4079 discrim->min_level = strtoul(cmp+2, NULL, 0);
4080 } else {
4081 discrim->min_level = strtoul(cmp+1, NULL, 0) + 1;
4082 }
4083 } else {
4084 reply("MSG_INVALID_CRITERIA", cmp);
4085 }
4086 #ifdef WITH_LDAP
4087 } else if (nickserv_conf.ldap_enable && !irccasecmp(argv[i], "inldap")) {
4088 i++;
4089 if(true_string(argv[i])) {
4090 discrim->inldap = 1;
4091 }
4092 else if (false_string(argv[i])) {
4093 discrim->inldap = 0;
4094 }
4095 else {
4096 reply("MSG_INVALID_BINARY", argv[i]);
4097 }
4098 #endif
4099 } else {
4100 reply("MSG_INVALID_CRITERIA", argv[i]);
4101 goto fail;
4102 }
4103 }
4104 return discrim;
4105 fail:
4106 free(discrim);
4107 return NULL;
4108 }
4109
4110 static int
4111 nickserv_discrim_match(struct nickserv_discrim *discrim, struct handle_info *hi)
4112 {
4113 if (((discrim->flags_on & hi->flags) != discrim->flags_on)
4114 || (discrim->flags_off & hi->flags)
4115 || (discrim->min_registered > hi->registered)
4116 || (discrim->max_registered < hi->registered)
4117 || (discrim->lastseen < (hi->users?now:hi->lastseen))
4118 || (discrim->handlemask && !match_ircglob(hi->handle, discrim->handlemask))
4119 || (discrim->emailmask && (!hi->email_addr || !match_ircglob(hi->email_addr, discrim->emailmask)))
4120 || (discrim->min_level > hi->opserv_level)
4121 || (discrim->max_level < hi->opserv_level)) {
4122 return 0;
4123 }
4124 if (discrim->hostmask) {
4125 unsigned int i;
4126 for (i=0; i<hi->masks->used; i++) {
4127 const char *mask = hi->masks->list[i];
4128 if ((discrim->hostmask_type == SUBSET)
4129 && (match_ircglobs(discrim->hostmask, mask))) break;
4130 else if ((discrim->hostmask_type == EXACT)
4131 && !irccasecmp(discrim->hostmask, mask)) break;
4132 else if ((discrim->hostmask_type == SUPERSET)
4133 && (match_ircglobs(mask, discrim->hostmask))) break;
4134 else if ((discrim->hostmask_type == LASTQUIT)
4135 && (match_ircglobs(discrim->hostmask, hi->last_quit_host))) break;
4136 }
4137 if (i==hi->masks->used) return 0;
4138 }
4139 if (discrim->nickmask) {
4140 struct nick_info *nick = hi->nicks;
4141 while (nick) {
4142 if (match_ircglob(nick->nick, discrim->nickmask)) break;
4143 nick = nick->next;
4144 }
4145 if (!nick) return 0;
4146 }
4147 #ifdef WITH_LDAP
4148 if(nickserv_conf.ldap_enable && discrim->inldap != 2) {
4149 int rc;
4150 rc = ldap_get_user_info(hi->handle, NULL);
4151 if(discrim->inldap == 1 && rc != LDAP_SUCCESS)
4152 return 0;
4153 if(discrim->inldap == 0 && rc == LDAP_SUCCESS)
4154 return 0;
4155 }
4156
4157 #endif
4158 return 1;
4159 }
4160
4161 static unsigned int
4162 nickserv_discrim_search(struct nickserv_discrim *discrim, discrim_search_func dsf, struct userNode *source)
4163 {
4164 dict_iterator_t it, next;
4165 unsigned int matched;
4166
4167 for (it = dict_first(nickserv_handle_dict), matched = 0;
4168 it && (matched < discrim->limit);
4169 it = next) {
4170 next = iter_next(it);
4171 if (nickserv_discrim_match(discrim, iter_data(it))) {
4172 dsf(source, iter_data(it));
4173 matched++;
4174 }
4175 }
4176 return matched;
4177 }
4178
4179 static void
4180 search_print_func(struct userNode *source, struct handle_info *match)
4181 {
4182 send_message(source, nickserv, "NSMSG_SEARCH_MATCH", match->handle);
4183 }
4184
4185 static void
4186 search_count_func(UNUSED_ARG(struct userNode *source), UNUSED_ARG(struct handle_info *match))
4187 {
4188 }
4189
4190 static void
4191 search_unregister_func (struct userNode *source, struct handle_info *match)
4192 {
4193 if (oper_has_access(source, nickserv, match->opserv_level, 0))
4194 nickserv_unregister_handle(match, source, nickserv); // XXX nickserv hard coded
4195 }
4196
4197 static void
4198 search_add2ldap_func (struct userNode *source, struct handle_info *match)
4199 {
4200 #ifdef WITH_LDAP
4201 int rc;
4202 if(match->email_addr && match->passwd && match->handle) {
4203 rc = ldap_do_add(match->handle, match->passwd, match->email_addr);
4204 if(rc != LDAP_SUCCESS) {
4205 send_message(source, nickserv, "NSMSG_LDAP_FAIL_ADD", match->handle, ldap_err2string(rc));
4206 }
4207 }
4208 #endif
4209 }
4210
4211 static int
4212 nickserv_sort_accounts_by_access(const void *a, const void *b)
4213 {
4214 const struct handle_info *hi_a = *(const struct handle_info**)a;
4215 const struct handle_info *hi_b = *(const struct handle_info**)b;
4216 if (hi_a->opserv_level != hi_b->opserv_level)
4217 return hi_b->opserv_level - hi_a->opserv_level;
4218 return irccasecmp(hi_a->handle, hi_b->handle);
4219 }
4220
4221 void
4222 nickserv_show_oper_accounts(struct userNode *user, struct svccmd *cmd)
4223 {
4224 struct handle_info_list hil;
4225 struct helpfile_table tbl;
4226 unsigned int ii;
4227 dict_iterator_t it;
4228 const char **ary;
4229
4230 memset(&hil, 0, sizeof(hil));
4231 for (it = dict_first(nickserv_handle_dict); it; it = iter_next(it)) {
4232 struct handle_info *hi = iter_data(it);
4233 if (hi->opserv_level)
4234 handle_info_list_append(&hil, hi);
4235 }
4236 qsort(hil.list, hil.used, sizeof(hil.list[0]), nickserv_sort_accounts_by_access);
4237 tbl.length = hil.used + 1;
4238 tbl.width = 2;
4239 tbl.flags = TABLE_NO_FREE | TABLE_REPEAT_ROWS | TABLE_REPEAT_HEADERS;
4240 tbl.contents = malloc(tbl.length * sizeof(tbl.contents[0]));
4241 tbl.contents[0] = ary = malloc(tbl.width * sizeof(ary[0]));
4242 ary[0] = "Account";
4243 ary[1] = "Level";
4244 for (ii = 0; ii < hil.used; ) {
4245 ary = malloc(tbl.width * sizeof(ary[0]));
4246 ary[0] = hil.list[ii]->handle;
4247 ary[1] = strtab(hil.list[ii]->opserv_level);
4248 tbl.contents[++ii] = ary;
4249 }
4250 table_send(cmd->parent->bot, user->nick, 0, NULL, tbl);
4251 /*reply("MSG_MATCH_COUNT", hil.used); */
4252 for (ii = 0; ii < hil.used; ii++)
4253 free(tbl.contents[ii]);
4254 free(tbl.contents);
4255 free(hil.list);
4256 }
4257
4258 static NICKSERV_FUNC(cmd_search)
4259 {
4260 struct nickserv_discrim *discrim;
4261 discrim_search_func action;
4262 struct svccmd *subcmd;
4263 unsigned int matches;
4264 char buf[MAXLEN];
4265
4266 NICKSERV_MIN_PARMS(3);
4267 sprintf(buf, "search %s", argv[1]);
4268 subcmd = dict_find(nickserv_service->commands, buf, NULL);
4269 if (!irccasecmp(argv[1], "print"))
4270 action = search_print_func;
4271 else if (!irccasecmp(argv[1], "count"))
4272 action = search_count_func;
4273 else if (!irccasecmp(argv[1], "unregister"))
4274 action = search_unregister_func;
4275 #ifdef WITH_LDAP
4276 else if (nickserv_conf.ldap_enable && !irccasecmp(argv[1], "add2ldap"))
4277 action = search_add2ldap_func;
4278 #endif
4279 else {
4280 reply("NSMSG_INVALID_ACTION", argv[1]);
4281 return 0;
4282 }
4283
4284 if (subcmd && !svccmd_can_invoke(user, nickserv, subcmd, NULL, SVCCMD_NOISY))
4285 return 0;
4286
4287 discrim = nickserv_discrim_create(cmd, user, argc-2, argv+2);
4288 if (!discrim)
4289 return 0;
4290
4291 if (action == search_print_func)
4292 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4293 else if (action == search_count_func)
4294 discrim->limit = INT_MAX;
4295
4296 matches = nickserv_discrim_search(discrim, action, user);
4297
4298 if (matches)
4299 reply("MSG_MATCH_COUNT", matches);
4300 else
4301 reply("MSG_NO_MATCHES");
4302
4303 free(discrim);
4304 return 0;
4305 }
4306
4307 static MODCMD_FUNC(cmd_checkpass)
4308 {
4309 struct handle_info *hi;
4310
4311 NICKSERV_MIN_PARMS(3);
4312 if (!(hi = get_handle_info(argv[1]))) {
4313 reply("MSG_HANDLE_UNKNOWN", argv[1]);
4314 return 0;
4315 }
4316 if (checkpass(argv[2], hi->passwd))
4317 reply("CHECKPASS_YES");
4318 else
4319 reply("CHECKPASS_NO");
4320 argv[2] = "****";
4321 return 1;
4322 }
4323
4324 static void
4325 nickserv_db_read_handle(char *handle, dict_t obj)
4326 {
4327 const char *str;
4328 struct string_list *masks, *slist, *ignores;
4329 struct handle_info *hi;
4330 struct userNode *authed_users;
4331 struct userData *channels;
4332 unsigned long int id;
4333 unsigned int ii;
4334 dict_t subdb;
4335 char *setter, *note;
4336 time_t date;
4337
4338 str = database_get_data(obj, KEY_ID, RECDB_QSTRING);
4339 id = str ? strtoul(str, NULL, 0) : 0;
4340 str = database_get_data(obj, KEY_PASSWD, RECDB_QSTRING);
4341 if (!str) {
4342 log_module(NS_LOG, LOG_WARNING, "did not find a password for %s -- skipping user.", handle);
4343 return;
4344 }
4345 if ((hi = get_handle_info(handle))) {
4346 authed_users = hi->users;
4347 channels = hi->channels;
4348 hi->users = NULL;
4349 hi->channels = NULL;
4350 dict_remove(nickserv_handle_dict, hi->handle);
4351 } else {
4352 authed_users = NULL;
4353 channels = NULL;
4354 }
4355 if(nickserv_conf.force_handles_lowercase)
4356 irc_strtolower(handle);
4357 hi = register_handle(handle, str, id);
4358 if (authed_users) {
4359 hi->users = authed_users;
4360 while (authed_users) {
4361 authed_users->handle_info = hi;
4362 authed_users = authed_users->next_authed;
4363 }
4364 }
4365 hi->channels = channels;
4366 masks = database_get_data(obj, KEY_MASKS, RECDB_STRING_LIST);
4367 hi->masks = masks ? string_list_copy(masks) : alloc_string_list(1);
4368 ignores = database_get_data(obj, KEY_IGNORES, RECDB_STRING_LIST);
4369 hi->ignores = ignores ? string_list_copy(ignores) : alloc_string_list(1);
4370 str = database_get_data(obj, KEY_MAXLOGINS, RECDB_QSTRING);
4371 hi->maxlogins = str ? strtoul(str, NULL, 0) : 0;
4372 str = database_get_data(obj, KEY_LANGUAGE, RECDB_QSTRING);
4373 hi->language = language_find(str ? str : "C");
4374 str = database_get_data(obj, KEY_OPSERV_LEVEL, RECDB_QSTRING);
4375 hi->opserv_level = str ? strtoul(str, NULL, 0) : 0;
4376 str = database_get_data(obj, KEY_INFO, RECDB_QSTRING);
4377 if (str)
4378 hi->infoline = strdup(str);
4379 str = database_get_data(obj, KEY_REGISTER_ON, RECDB_QSTRING);
4380 hi->registered = str ? (time_t)strtoul(str, NULL, 0) : now;
4381 str = database_get_data(obj, KEY_LAST_SEEN, RECDB_QSTRING);
4382 hi->lastseen = str ? (time_t)strtoul(str, NULL, 0) : hi->registered;
4383 /* We want to read the nicks even if disable_nicks is set. This is so
4384 * that we don't lose the nick data entirely. */
4385 slist = database_get_data(obj, KEY_NICKS, RECDB_STRING_LIST);
4386 if (slist) {
4387 for (ii=0; ii<slist->used; ii++)
4388 register_nick(slist->list[ii], hi);
4389 }
4390 str = database_get_data(obj, KEY_FLAGS, RECDB_QSTRING);
4391 if (str) {
4392 for (ii=0; str[ii]; ii++)
4393 hi->flags |= 1 << (handle_inverse_flags[(unsigned char)str[ii]] - 1);
4394 }
4395 str = database_get_data(obj, KEY_USERLIST_STYLE, RECDB_QSTRING);
4396 hi->userlist_style = str ? str[0] : HI_DEFAULT_STYLE;
4397 str = database_get_data(obj, KEY_ANNOUNCEMENTS, RECDB_QSTRING);
4398 hi->announcements = str ? str[0] : '?';
4399 str = database_get_data(obj, KEY_SCREEN_WIDTH, RECDB_QSTRING);
4400 hi->screen_width = str ? strtoul(str, NULL, 0) : 0;
4401 str = database_get_data(obj, KEY_TABLE_WIDTH, RECDB_QSTRING);
4402 hi->table_width = str ? strtoul(str, NULL, 0) : 0;
4403 str = database_get_data(obj, KEY_LAST_QUIT_HOST, RECDB_QSTRING);
4404 if (!str)
4405 str = database_get_data(obj, KEY_LAST_AUTHED_HOST, RECDB_QSTRING);
4406 if (str)
4407 safestrncpy(hi->last_quit_host, str, sizeof(hi->last_quit_host));
4408 str = database_get_data(obj, KEY_EMAIL_ADDR, RECDB_QSTRING);
4409 if (str)
4410 nickserv_set_email_addr(hi, str);
4411 str = database_get_data(obj, KEY_EPITHET, RECDB_QSTRING);
4412 if (str)
4413 hi->epithet = strdup(str);
4414 subdb = database_get_data(obj, KEY_NOTE_NOTE, RECDB_OBJECT);
4415 if (subdb) {
4416 setter = database_get_data(subdb, KEY_NOTE_SETTER, RECDB_QSTRING);
4417 str = database_get_data(subdb, KEY_NOTE_DATE, RECDB_QSTRING);
4418 date = str ? (time_t)strtoul(str, NULL, 0) : now;
4419 note = database_get_data(subdb, KEY_NOTE_NOTE, RECDB_QSTRING);
4420 if (setter && date && note)
4421 {
4422 if (!(hi->note = nickserv_add_note(setter, date, note)))
4423 hi->note = NULL;
4424 }
4425 }
4426
4427 str = database_get_data(obj, KEY_FAKEHOST, RECDB_QSTRING);
4428 if (str)
4429 hi->fakehost = strdup(str);
4430
4431 subdb = database_get_data(obj, KEY_COOKIE, RECDB_OBJECT);
4432 if (subdb) {
4433 const char *data, *type, *expires, *cookie_str;
4434 struct handle_cookie *cookie;
4435
4436 cookie = calloc(1, sizeof(*cookie));
4437 type = database_get_data(subdb, KEY_COOKIE_TYPE, RECDB_QSTRING);
4438 data = database_get_data(subdb, KEY_COOKIE_DATA, RECDB_QSTRING);
4439 expires = database_get_data(subdb, KEY_COOKIE_EXPIRES, RECDB_QSTRING);
4440 cookie_str = database_get_data(subdb, KEY_COOKIE, RECDB_QSTRING);
4441 if (!type || !expires || !cookie_str) {
4442 log_module(NS_LOG, LOG_ERROR, "Missing field(s) from cookie for account %s; dropping cookie.", hi->handle);
4443 goto cookie_out;
4444 }
4445 if (!irccasecmp(type, KEY_ACTIVATION))
4446 cookie->type = ACTIVATION;
4447 else if (!irccasecmp(type, KEY_PASSWORD_CHANGE))
4448 cookie->type = PASSWORD_CHANGE;
4449 else if (!irccasecmp(type, KEY_EMAIL_CHANGE))
4450 cookie->type = EMAIL_CHANGE;
4451 else if (!irccasecmp(type, KEY_ALLOWAUTH))
4452 cookie->type = ALLOWAUTH;
4453 else {
4454 log_module(NS_LOG, LOG_ERROR, "Invalid cookie type %s for account %s; dropping cookie.", type, handle);
4455 goto cookie_out;
4456 }
4457 cookie->expires = strtoul(expires, NULL, 0);
4458 if (cookie->expires < now)
4459 goto cookie_out;
4460 if (data)
4461 cookie->data = strdup(data);
4462 safestrncpy(cookie->cookie, cookie_str, sizeof(cookie->cookie));
4463 cookie->hi = hi;
4464 cookie_out:
4465 if (cookie->hi)
4466 nickserv_bake_cookie(cookie);
4467 else
4468 nickserv_free_cookie(cookie);
4469 }
4470 }
4471
4472 static int
4473 nickserv_saxdb_read(dict_t db) {
4474 dict_iterator_t it;
4475 struct record_data *rd;
4476 char *handle;
4477
4478 for (it=dict_first(db); it; it=iter_next(it)) {
4479 rd = iter_data(it);
4480 handle = strdup(iter_key(it));
4481 nickserv_db_read_handle(handle, rd->d.object);
4482 free(handle);
4483 }
4484 return 0;
4485 }
4486
4487 static NICKSERV_FUNC(cmd_mergedb)
4488 {
4489 struct timeval start, stop;
4490 dict_t db;
4491
4492 NICKSERV_MIN_PARMS(2);
4493 gettimeofday(&start, NULL);
4494 if (!(db = parse_database(argv[1]))) {
4495 reply("NSMSG_DB_UNREADABLE", argv[1]);
4496 return 0;
4497 }
4498 nickserv_saxdb_read(db);
4499 free_database(db);
4500 gettimeofday(&stop, NULL);
4501 stop.tv_sec -= start.tv_sec;
4502 stop.tv_usec -= start.tv_usec;
4503 if (stop.tv_usec < 0) {
4504 stop.tv_sec -= 1;
4505 stop.tv_usec += 1000000;
4506 }
4507 reply("NSMSG_DB_MERGED", argv[1], stop.tv_sec, stop.tv_usec/1000);
4508 return 1;
4509 }
4510
4511 static void
4512 expire_handles(UNUSED_ARG(void *data))
4513 {
4514 dict_iterator_t it, next;
4515 time_t expiry;
4516 struct handle_info *hi;
4517
4518 for (it=dict_first(nickserv_handle_dict); it; it=next) {
4519 next = iter_next(it);
4520 hi = iter_data(it);
4521 if ((hi->opserv_level > 0)
4522 || hi->users
4523 || HANDLE_FLAGGED(hi, FROZEN)
4524 || HANDLE_FLAGGED(hi, NODELETE)) {
4525 continue;
4526 }
4527 expiry = hi->channels ? nickserv_conf.handle_expire_delay : nickserv_conf.nochan_handle_expire_delay;
4528 if ((now - hi->lastseen) > expiry) {
4529 log_module(NS_LOG, LOG_INFO, "Expiring account %s for inactivity.", hi->handle);
4530 nickserv_unregister_handle(hi, NULL, NULL);
4531 }
4532 }
4533
4534 if (nickserv_conf.handle_expire_frequency)
4535 timeq_add(now + nickserv_conf.handle_expire_frequency, expire_handles, NULL);
4536 }
4537
4538 static void
4539 nickserv_load_dict(const char *fname)
4540 {
4541 FILE *file;
4542 char line[128];
4543 if (!(file = fopen(fname, "r"))) {
4544 log_module(NS_LOG, LOG_ERROR, "Unable to open dictionary file %s: %s", fname, strerror(errno));
4545 return;
4546 }
4547 while (!feof(file)) {
4548 fgets(line, sizeof(line), file);
4549 if (!line[0])
4550 continue;
4551 if (line[strlen(line)-1] == '\n')
4552 line[strlen(line)-1] = 0;
4553 dict_insert(nickserv_conf.weak_password_dict, strdup(line), NULL);
4554 }
4555 fclose(file);
4556 log_module(NS_LOG, LOG_INFO, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf.weak_password_dict));
4557 }
4558
4559 static enum reclaim_action
4560 reclaim_action_from_string(const char *str) {
4561 if (!str)
4562 return RECLAIM_NONE;
4563 else if (!irccasecmp(str, "warn"))
4564 return RECLAIM_WARN;
4565 else if (!irccasecmp(str, "svsnick"))
4566 return RECLAIM_SVSNICK;
4567 else if (!irccasecmp(str, "kill"))
4568 return RECLAIM_KILL;
4569 else
4570 return RECLAIM_NONE;
4571 }
4572
4573 static void
4574 nickserv_conf_read(void)
4575 {
4576 dict_t conf_node, child;
4577 const char *str;
4578 dict_iterator_t it;
4579 struct string_list *strlist;
4580
4581 if (!(conf_node = conf_get_data(NICKSERV_CONF_NAME, RECDB_OBJECT))) {
4582 log_module(NS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME);
4583 return;
4584 }
4585 str = database_get_data(conf_node, KEY_VALID_HANDLE_REGEX, RECDB_QSTRING);
4586 if (!str)
4587 str = database_get_data(conf_node, KEY_VALID_ACCOUNT_REGEX, RECDB_QSTRING);
4588 if (nickserv_conf.valid_handle_regex_set)
4589 regfree(&nickserv_conf.valid_handle_regex);
4590 if (str) {
4591 int err = regcomp(&nickserv_conf.valid_handle_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
4592 nickserv_conf.valid_handle_regex_set = !err;
4593 if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_account_regex (error %d)", err);
4594 } else {
4595 nickserv_conf.valid_handle_regex_set = 0;
4596 }
4597 str = database_get_data(conf_node, KEY_VALID_NICK_REGEX, RECDB_QSTRING);
4598 if (nickserv_conf.valid_nick_regex_set)
4599 regfree(&nickserv_conf.valid_nick_regex);
4600 if (str) {
4601 int err = regcomp(&nickserv_conf.valid_nick_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
4602 nickserv_conf.valid_nick_regex_set = !err;
4603 if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_nick_regex (error %d)", err);
4604 } else {
4605 nickserv_conf.valid_nick_regex_set = 0;
4606 }
4607 str = database_get_data(conf_node, KEY_VALID_FAKEHOST_REGEX, RECDB_QSTRING);
4608 if (nickserv_conf.valid_fakehost_regex_set)
4609 regfree(&nickserv_conf.valid_fakehost_regex);
4610 if (str) {
4611 int err = regcomp(&nickserv_conf.valid_fakehost_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
4612 nickserv_conf.valid_fakehost_regex_set = !err;
4613 if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_fakehost_regex (error %d)", err);
4614 } else {
4615 nickserv_conf.valid_fakehost_regex_set = 0;
4616 }
4617 str = database_get_data(conf_node, KEY_NICKS_PER_HANDLE, RECDB_QSTRING);
4618 if (!str)
4619 str = database_get_data(conf_node, KEY_NICKS_PER_ACCOUNT, RECDB_QSTRING);
4620 nickserv_conf.nicks_per_handle = str ? strtoul(str, NULL, 0) : 4;
4621 str = database_get_data(conf_node, KEY_DISABLE_NICKS, RECDB_QSTRING);
4622 nickserv_conf.disable_nicks = str ? strtoul(str, NULL, 0) : 0;
4623 str = database_get_data(conf_node, KEY_DEFAULT_HOSTMASK, RECDB_QSTRING);
4624 nickserv_conf.default_hostmask = str ? !disabled_string(str) : 0;
4625 str = database_get_data(conf_node, KEY_PASSWORD_MIN_LENGTH, RECDB_QSTRING);
4626 nickserv_conf.password_min_length = str ? strtoul(str, NULL, 0) : 0;
4627 str = database_get_data(conf_node, KEY_PASSWORD_MIN_DIGITS, RECDB_QSTRING);
4628 nickserv_conf.password_min_digits = str ? strtoul(str, NULL, 0) : 0;
4629 str = database_get_data(conf_node, KEY_PASSWORD_MIN_UPPER, RECDB_QSTRING);
4630 nickserv_conf.password_min_upper = str ? strtoul(str, NULL, 0) : 0;
4631 str = database_get_data(conf_node, KEY_PASSWORD_MIN_LOWER, RECDB_QSTRING);
4632 nickserv_conf.password_min_lower = str ? strtoul(str, NULL, 0) : 0;
4633 str = database_get_data(conf_node, KEY_DB_BACKUP_FREQ, RECDB_QSTRING);
4634 nickserv_conf.db_backup_frequency = str ? ParseInterval(str) : 7200;
4635 str = database_get_data(conf_node, KEY_MODOPER_LEVEL, RECDB_QSTRING);
4636 nickserv_conf.modoper_level = str ? strtoul(str, NULL, 0) : 900;
4637 str = database_get_data(conf_node, KEY_SET_EPITHET_LEVEL, RECDB_QSTRING);
4638 nickserv_conf.set_epithet_level = str ? strtoul(str, NULL, 0) : 1;
4639 str = database_get_data(conf_node, KEY_SET_TITLE_LEVEL, RECDB_QSTRING);
4640 nickserv_conf.set_title_level = str ? strtoul(str, NULL, 0) : 900;
4641 str = database_get_data(conf_node, KEY_SET_FAKEHOST_LEVEL, RECDB_QSTRING);
4642 nickserv_conf.set_fakehost_level = str ? strtoul(str, NULL, 0) : 1000;
4643 str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_FREQ, RECDB_QSTRING);
4644 if (!str)
4645 str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_FREQ, RECDB_QSTRING);
4646 nickserv_conf.handle_expire_frequency = str ? ParseInterval(str) : 86400;
4647 str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_DELAY, RECDB_QSTRING);
4648 if (!str)
4649 str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
4650 nickserv_conf.handle_expire_delay = str ? ParseInterval(str) : 86400*30;
4651 str = database_get_data(conf_node, KEY_NOCHAN_HANDLE_EXPIRE_DELAY, RECDB_QSTRING);
4652 if (!str)
4653 str = database_get_data(conf_node, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
4654 nickserv_conf.nochan_handle_expire_delay = str ? ParseInterval(str) : 86400*15;
4655 str = database_get_data(conf_node, "warn_clone_auth", RECDB_QSTRING);
4656 nickserv_conf.warn_clone_auth = str ? !disabled_string(str) : 1;
4657 str = database_get_data(conf_node, "default_maxlogins", RECDB_QSTRING);
4658 nickserv_conf.default_maxlogins = str ? strtoul(str, NULL, 0) : 2;
4659 str = database_get_data(conf_node, "hard_maxlogins", RECDB_QSTRING);
4660 nickserv_conf.hard_maxlogins = str ? strtoul(str, NULL, 0) : 10;
4661 if (!nickserv_conf.disable_nicks) {
4662 str = database_get_data(conf_node, "reclaim_action", RECDB_QSTRING);
4663 nickserv_conf.reclaim_action = str ? reclaim_action_from_string(str) : RECLAIM_NONE;
4664 str = database_get_data(conf_node, "warn_nick_owned", RECDB_QSTRING);
4665 nickserv_conf.warn_nick_owned = str ? enabled_string(str) : 0;
4666 str = database_get_data(conf_node, "auto_reclaim_action", RECDB_QSTRING);
4667 nickserv_conf.auto_reclaim_action = str ? reclaim_action_from_string(str) : RECLAIM_NONE;
4668 str = database_get_data(conf_node, "auto_reclaim_delay", RECDB_QSTRING);
4669 nickserv_conf.auto_reclaim_delay = str ? ParseInterval(str) : 0;
4670 }
4671 child = database_get_data(conf_node, KEY_FLAG_LEVELS, RECDB_OBJECT);
4672 for (it=dict_first(child); it; it=iter_next(it)) {
4673 const char *key = iter_key(it), *value;
4674 unsigned char flag;
4675 int pos;
4676
4677 if (!strncasecmp(key, "uc_", 3))
4678 flag = toupper(key[3]);
4679 else if (!strncasecmp(key, "lc_", 3))
4680 flag = tolower(key[3]);
4681 else
4682 flag = key[0];
4683
4684 if ((pos = handle_inverse_flags[flag])) {
4685 value = GET_RECORD_QSTRING((struct record_data*)iter_data(it));
4686 flag_access_levels[pos - 1] = strtoul(value, NULL, 0);
4687 }
4688 }
4689 if (nickserv_conf.weak_password_dict)
4690 dict_delete(nickserv_conf.weak_password_dict);
4691 nickserv_conf.weak_password_dict = dict_new();
4692 dict_set_free_keys(nickserv_conf.weak_password_dict, free);
4693 dict_insert(nickserv_conf.weak_password_dict, strdup("password"), NULL);
4694 dict_insert(nickserv_conf.weak_password_dict, strdup("<password>"), NULL);
4695 str = database_get_data(conf_node, KEY_DICT_FILE, RECDB_QSTRING);
4696 if (str)
4697 nickserv_load_dict(str);
4698 str = database_get_data(conf_node, KEY_NICK, RECDB_QSTRING);
4699 if (nickserv && str)
4700 NickChange(nickserv, str, 0);
4701 str = database_get_data(conf_node, KEY_AUTOGAG_ENABLED, RECDB_QSTRING);
4702 nickserv_conf.autogag_enabled = str ? strtoul(str, NULL, 0) : 1;
4703 str = database_get_data(conf_node, KEY_AUTOGAG_DURATION, RECDB_QSTRING);
4704 nickserv_conf.autogag_duration = str ? ParseInterval(str) : 1800;
4705 str = database_get_data(conf_node, KEY_EMAIL_VISIBLE_LEVEL, RECDB_QSTRING);
4706 nickserv_conf.email_visible_level = str ? strtoul(str, NULL, 0) : 800;
4707 str = database_get_data(conf_node, KEY_EMAIL_ENABLED, RECDB_QSTRING);
4708 nickserv_conf.email_enabled = str ? enabled_string(str) : 0;
4709 str = database_get_data(conf_node, KEY_SYNC_LOG, RECDB_QSTRING);
4710 nickserv_conf.sync_log = str ? enabled_string(str) : 0;
4711 str = database_get_data(conf_node, KEY_COOKIE_TIMEOUT, RECDB_QSTRING);
4712 nickserv_conf.cookie_timeout = str ? ParseInterval(str) : 24*3600;
4713 str = database_get_data(conf_node, KEY_EMAIL_REQUIRED, RECDB_QSTRING);
4714 nickserv_conf.email_required = (nickserv_conf.email_enabled && str) ? enabled_string(str) : 0;
4715 str = database_get_data(conf_node, KEY_ACCOUNTS_PER_EMAIL, RECDB_QSTRING);
4716 nickserv_conf.handles_per_email = str ? strtoul(str, NULL, 0) : 1;
4717 str = database_get_data(conf_node, KEY_EMAIL_SEARCH_LEVEL, RECDB_QSTRING);
4718 nickserv_conf.email_search_level = str ? strtoul(str, NULL, 0) : 600;
4719 str = database_get_data(conf_node, KEY_TITLEHOST_SUFFIX, RECDB_QSTRING);
4720 nickserv_conf.titlehost_suffix = str ? str : "example.net";
4721
4722 free_string_list(nickserv_conf.denied_fakehost_words);
4723 strlist = database_get_data(conf_node, KEY_DENIED_FAKEHOST_WORDS, RECDB_STRING_LIST);
4724 if(strlist)
4725 strlist = string_list_copy(strlist);
4726 else {
4727 strlist = alloc_string_list(4);
4728 string_list_append(strlist, strdup("sex"));
4729 string_list_append(strlist, strdup("fuck"));
4730 }
4731 nickserv_conf.denied_fakehost_words = strlist;
4732
4733 str = database_get_data(conf_node, KEY_DEFAULT_STYLE, RECDB_QSTRING);
4734 nickserv_conf.default_style = str ? str[0] : HI_DEFAULT_STYLE;
4735
4736 str = database_get_data(conf_node, KEY_AUTO_OPER, RECDB_QSTRING);
4737 nickserv_conf.auto_oper = str ? str : "";
4738
4739 str = database_get_data(conf_node, KEY_AUTO_ADMIN, RECDB_QSTRING);
4740 nickserv_conf.auto_admin = str ? str : "";
4741
4742 str = conf_get_data("server/network", RECDB_QSTRING);
4743 nickserv_conf.network_name = str ? str : "some IRC network";
4744 if (!nickserv_conf.auth_policer_params) {
4745 nickserv_conf.auth_policer_params = policer_params_new();
4746 policer_params_set(nickserv_conf.auth_policer_params, "size", "5");
4747 policer_params_set(nickserv_conf.auth_policer_params, "drain-rate", "0.05");
4748 }
4749 child = database_get_data(conf_node, KEY_AUTH_POLICER, RECDB_OBJECT);
4750 for (it=dict_first(child); it; it=iter_next(it))
4751 set_policer_param(iter_key(it), iter_data(it), nickserv_conf.auth_policer_params);
4752
4753 str = database_get_data(conf_node, KEY_LDAP_ENABLE, RECDB_QSTRING);
4754 nickserv_conf.ldap_enable = str ? strtoul(str, NULL, 0) : 0;
4755
4756 str = database_get_data(conf_node, KEY_FORCE_HANDLES_LOWERCASE, RECDB_QSTRING);
4757 nickserv_conf.force_handles_lowercase = str ? strtol(str, NULL, 0) : 0;
4758
4759 #ifndef WITH_LDAP
4760 if(nickserv_conf.ldap_enable > 0) {
4761 /* ldap is enabled but not compiled in - error out */
4762 log_module(MAIN_LOG, LOG_ERROR, "ldap is enabled in config, but not compiled in!");
4763 nickserv_conf.ldap_enable = 0;
4764 sleep(5);
4765 }
4766 #endif
4767
4768 #ifdef WITH_LDAP
4769 str = database_get_data(conf_node, KEY_LDAP_URI, RECDB_QSTRING);
4770 nickserv_conf.ldap_uri = str ? str : "";
4771
4772 str = database_get_data(conf_node, KEY_LDAP_BASE, RECDB_QSTRING);
4773 nickserv_conf.ldap_base = str ? str : "";
4774
4775 str = database_get_data(conf_node, KEY_LDAP_DN_FMT, RECDB_QSTRING);
4776 nickserv_conf.ldap_dn_fmt = str ? str : "";
4777
4778 str = database_get_data(conf_node, KEY_LDAP_VERSION, RECDB_QSTRING);
4779 nickserv_conf.ldap_version = str ? strtoul(str, NULL, 0) : 3;
4780
4781 str = database_get_data(conf_node, KEY_LDAP_AUTOCREATE, RECDB_QSTRING);
4782 nickserv_conf.ldap_autocreate = str ? strtoul(str, NULL, 0) : 0;
4783
4784 str = database_get_data(conf_node, KEY_LDAP_TIMEOUT, RECDB_QSTRING);
4785 nickserv_conf.ldap_timeout = str ? strtoul(str, NULL, 0) : 5;
4786
4787 str = database_get_data(conf_node, KEY_LDAP_ADMIN_DN, RECDB_QSTRING);
4788 nickserv_conf.ldap_admin_dn = str ? str : "";
4789
4790 str = database_get_data(conf_node, KEY_LDAP_ADMIN_PASS, RECDB_QSTRING);
4791 nickserv_conf.ldap_admin_pass = str ? str : "";
4792
4793 str = database_get_data(conf_node, KEY_LDAP_FIELD_ACCOUNT, RECDB_QSTRING);
4794 nickserv_conf.ldap_field_account = str ? str : "";
4795
4796 str = database_get_data(conf_node, KEY_LDAP_FIELD_PASSWORD, RECDB_QSTRING);
4797 nickserv_conf.ldap_field_password = str ? str : "";
4798
4799 str = database_get_data(conf_node, KEY_LDAP_FIELD_EMAIL, RECDB_QSTRING);
4800 nickserv_conf.ldap_field_email = str ? str : "";
4801
4802 str = database_get_data(conf_node, KEY_LDAP_OPER_GROUP_DN, RECDB_QSTRING);
4803 nickserv_conf.ldap_oper_group_dn = str ? str : "";
4804
4805 str = database_get_data(conf_node, KEY_LDAP_OPER_GROUP_LEVEL, RECDB_QSTRING);
4806 nickserv_conf.ldap_oper_group_level = str ? strtoul(str, NULL, 0) : 99;
4807
4808 str = database_get_data(conf_node, KEY_LDAP_FIELD_GROUP_MEMBER, RECDB_QSTRING);
4809 nickserv_conf.ldap_field_group_member = str ? str : "";
4810
4811 free_string_list(nickserv_conf.ldap_object_classes);
4812 strlist = database_get_data(conf_node, KEY_LDAP_OBJECT_CLASSES, RECDB_STRING_LIST);
4813 if(strlist)
4814 strlist = string_list_copy(strlist);
4815 else {
4816 strlist = alloc_string_list(4);
4817 string_list_append(strlist, strdup("top"));
4818 }
4819 nickserv_conf.ldap_object_classes = strlist;
4820
4821 #endif
4822
4823 }
4824
4825 static void
4826 nickserv_reclaim(struct userNode *user, struct nick_info *ni, enum reclaim_action action) {
4827 const char *msg;
4828 char newnick[NICKLEN+1];
4829
4830 assert(user);
4831 assert(ni);
4832 switch (action) {
4833 case RECLAIM_NONE:
4834 /* do nothing */
4835 break;
4836 case RECLAIM_WARN:
4837 send_message(user, nickserv, "NSMSG_RECLAIM_WARN", ni->nick, ni->owner->handle);
4838 break;
4839 case RECLAIM_SVSNICK:
4840 do {
4841 snprintf(newnick, sizeof(newnick), "Guest%d", rand()%10000);
4842 } while (GetUserH(newnick));
4843 irc_svsnick(nickserv, user, newnick);
4844 break;
4845 case RECLAIM_KILL:
4846 msg = user_find_message(user, "NSMSG_RECLAIM_KILL");
4847 irc_kill(nickserv, user, msg);
4848 break;
4849 }
4850 }
4851
4852 static void
4853 nickserv_reclaim_p(void *data) {
4854 struct userNode *user = data;
4855 struct nick_info *ni = get_nick_info(user->nick);
4856 if (ni)
4857 nickserv_reclaim(user, ni, nickserv_conf.auto_reclaim_action);
4858 }
4859
4860 static int
4861 check_user_nick(struct userNode *user) {
4862 struct nick_info *ni;
4863 user->modes &= ~FLAGS_REGNICK;
4864 if (!(ni = get_nick_info(user->nick)))
4865 return 0;
4866 if (user->handle_info == ni->owner) {
4867 user->modes |= FLAGS_REGNICK;
4868 irc_regnick(user);
4869 return 0;
4870 }
4871 if (nickserv_conf.warn_nick_owned)
4872 send_message(user, nickserv, "NSMSG_RECLAIM_WARN", ni->nick, ni->owner->handle);
4873 if (nickserv_conf.auto_reclaim_action == RECLAIM_NONE)
4874 return 0;
4875 if (nickserv_conf.auto_reclaim_delay)
4876 timeq_add(now + nickserv_conf.auto_reclaim_delay, nickserv_reclaim_p, user);
4877 else
4878 nickserv_reclaim(user, ni, nickserv_conf.auto_reclaim_action);
4879 return 0;
4880 }
4881
4882 int
4883 handle_new_user(struct userNode *user)
4884 {
4885 return check_user_nick(user);
4886 }
4887
4888 void
4889 handle_account(struct userNode *user, const char *stamp)
4890 {
4891 struct handle_info *hi;
4892 char *colon;
4893
4894 #ifdef WITH_PROTOCOL_P10
4895 time_t timestamp = 0;
4896
4897 colon = strchr(stamp, ':');
4898 if(colon && colon[1])
4899 {
4900 *colon = 0;
4901 timestamp = atoi(colon+1);
4902 }
4903 hi = dict_find(nickserv_handle_dict, stamp, NULL);
4904 if(hi && timestamp && hi->registered != timestamp)
4905 {
4906 log_module(MAIN_LOG, LOG_WARNING, "%s using account %s but timestamp does not match %lu is not %lu.", user->nick, stamp, timestamp, hi->registered);
4907 return;
4908 }
4909 #else
4910 hi = dict_find(nickserv_id_dict, stamp, NULL);
4911 log_module(MAIN_LOG, LOG_WARNING, "Using non-P10 code in accounts, not tested at all!");
4912 #endif
4913
4914 if (hi) {
4915 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
4916 return;
4917 }
4918 set_user_handle_info(user, hi, 0);
4919 } else {
4920 log_module(MAIN_LOG, LOG_WARNING, "%s had unknown account stamp %s.", user->nick, stamp);
4921 }
4922 }
4923
4924 void
4925 handle_nick_change(struct userNode *user, const char *old_nick)
4926 {
4927 struct handle_info *hi;
4928
4929 if ((hi = dict_find(nickserv_allow_auth_dict, old_nick, 0))) {
4930 dict_remove(nickserv_allow_auth_dict, old_nick);
4931 dict_insert(nickserv_allow_auth_dict, user->nick, hi);
4932 }
4933 timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
4934 check_user_nick(user);
4935 }
4936
4937 void
4938 nickserv_remove_user(struct userNode *user, UNUSED_ARG(struct userNode *killer), UNUSED_ARG(const char *why))
4939 {
4940 dict_remove(nickserv_allow_auth_dict, user->nick);
4941 timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
4942 set_user_handle_info(user, NULL, 0);
4943 }
4944
4945 static struct modcmd *
4946 nickserv_define_func(const char *name, modcmd_func_t func, int min_level, int must_auth, int must_be_qualified)
4947 {
4948 if (min_level > 0) {
4949 char buf[16];
4950 sprintf(buf, "%u", min_level);
4951 if (must_be_qualified) {
4952 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "level", buf, "flags", "+qualified,+loghostmask", NULL);
4953 } else {
4954 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "level", buf, NULL);
4955 }
4956 } else if (min_level == 0) {
4957 if (must_be_qualified) {
4958 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "flags", "+helping", NULL);
4959 } else {
4960 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "flags", "+helping", NULL);
4961 }
4962 } else {
4963 if (must_be_qualified) {
4964 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "flags", "+qualified,+loghostmask", NULL);
4965 } else {
4966 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), NULL);
4967 }
4968 }
4969 }
4970
4971 static void
4972 nickserv_db_cleanup(void)
4973 {
4974 unreg_del_user_func(nickserv_remove_user);
4975 userList_clean(&curr_helpers);
4976 policer_params_delete(nickserv_conf.auth_policer_params);
4977 dict_delete(nickserv_handle_dict);
4978 dict_delete(nickserv_nick_dict);
4979 dict_delete(nickserv_opt_dict);
4980 dict_delete(nickserv_allow_auth_dict);
4981 dict_delete(nickserv_email_dict);
4982 dict_delete(nickserv_id_dict);
4983 dict_delete(nickserv_conf.weak_password_dict);
4984 free(auth_func_list);
4985 free(unreg_func_list);
4986 free(rf_list);
4987 free(allowauth_func_list);
4988 free(handle_merge_func_list);
4989 free(failpw_func_list);
4990 if (nickserv_conf.valid_handle_regex_set)
4991 regfree(&nickserv_conf.valid_handle_regex);
4992 if (nickserv_conf.valid_nick_regex_set)
4993 regfree(&nickserv_conf.valid_nick_regex);
4994 }
4995
4996 void
4997 init_nickserv(const char *nick)
4998 {
4999 struct chanNode *chan;
5000 unsigned int i;
5001 NS_LOG = log_register_type("NickServ", "file:nickserv.log");
5002 reg_new_user_func(handle_new_user);
5003 reg_nick_change_func(handle_nick_change);
5004 reg_del_user_func(nickserv_remove_user);
5005 reg_account_func(handle_account);
5006
5007 /* set up handle_inverse_flags */
5008 memset(handle_inverse_flags, 0, sizeof(handle_inverse_flags));
5009 for (i=0; handle_flags[i]; i++) {
5010 handle_inverse_flags[(unsigned char)handle_flags[i]] = i + 1;
5011 flag_access_levels[i] = 0;
5012 }
5013
5014 conf_register_reload(nickserv_conf_read);
5015 nickserv_opt_dict = dict_new();
5016 nickserv_email_dict = dict_new();
5017
5018 dict_set_free_keys(nickserv_email_dict, free);
5019 dict_set_free_data(nickserv_email_dict, nickserv_free_email_addr);
5020
5021 nickserv_module = module_register("NickServ", NS_LOG, "nickserv.help", NULL);
5022 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
5023 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
5024 * a big pain to disable since its nolonger in the config file. ) -Rubin
5025 */
5026 modcmd_register(nickserv_module, "AUTH", cmd_auth, 2, MODCMD_KEEP_BOUND, "flags", "+loghostmask", NULL);
5027 nickserv_define_func("ALLOWAUTH", cmd_allowauth, 0, 1, 0);
5028 nickserv_define_func("REGISTER", cmd_register, -1, 0, 0);
5029 nickserv_define_func("OREGISTER", cmd_oregister, 0, 1, 0);
5030 nickserv_define_func("UNREGISTER", cmd_unregister, -1, 1, 0);
5031 nickserv_define_func("OUNREGISTER", cmd_ounregister, 0, 1, 0);
5032 nickserv_define_func("ADDMASK", cmd_addmask, -1, 1, 0);
5033 nickserv_define_func("OADDMASK", cmd_oaddmask, 0, 1, 0);
5034 nickserv_define_func("DELMASK", cmd_delmask, -1, 1, 0);
5035 nickserv_define_func("ODELMASK", cmd_odelmask, 0, 1, 0);
5036 nickserv_define_func("PASS", cmd_pass, -1, 1, 0);
5037 nickserv_define_func("SET", cmd_set, -1, 1, 0);
5038 nickserv_define_func("OSET", cmd_oset, 0, 1, 0);
5039 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo, -1, 0, 0);
5040 nickserv_define_func("USERINFO", cmd_userinfo, -1, 1, 0);
5041 nickserv_define_func("RENAME", cmd_rename_handle, -1, 1, 0);
5042 nickserv_define_func("VACATION", cmd_vacation, -1, 1, 0);
5043 nickserv_define_func("MERGE", cmd_merge, 0, 1, 0);
5044 if (!nickserv_conf.disable_nicks) {
5045 /* nick management commands */
5046 nickserv_define_func("REGNICK", cmd_regnick, -1, 1, 0);
5047 nickserv_define_func("OREGNICK", cmd_oregnick, 0, 1, 0);
5048 nickserv_define_func("UNREGNICK", cmd_unregnick, -1, 1, 0);
5049 nickserv_define_func("OUNREGNICK", cmd_ounregnick, 0, 1, 0);
5050 nickserv_define_func("NICKINFO", cmd_nickinfo, -1, 1, 0);
5051 nickserv_define_func("RECLAIM", cmd_reclaim, -1, 1, 0);
5052 }
5053 if (nickserv_conf.email_enabled) {
5054 nickserv_define_func("AUTHCOOKIE", cmd_authcookie, -1, 0, 0);
5055 nickserv_define_func("RESETPASS", cmd_resetpass, -1, 0, 0);
5056 nickserv_define_func("COOKIE", cmd_cookie, -1, 0, 0);
5057 nickserv_define_func("DELCOOKIE", cmd_delcookie, -1, 1, 0);
5058 nickserv_define_func("ODELCOOKIE", cmd_odelcookie, 0, 1, 0);
5059 dict_insert(nickserv_opt_dict, "EMAIL", opt_email);
5060 }
5061 nickserv_define_func("GHOST", cmd_ghost, -1, 1, 0);
5062 /* ignore commands */
5063 nickserv_define_func("ADDIGNORE", cmd_addignore, -1, 1, 0);
5064 nickserv_define_func("OADDIGNORE", cmd_oaddignore, 0, 1, 0);
5065 nickserv_define_func("DELIGNORE", cmd_delignore, -1, 1, 0);
5066 nickserv_define_func("ODELIGNORE", cmd_odelignore, 0, 1, 0);
5067 /* miscellaneous commands */
5068 nickserv_define_func("STATUS", cmd_status, -1, 0, 0);
5069 nickserv_define_func("SEARCH", cmd_search, 100, 1, 0);
5070 nickserv_define_func("SEARCH UNREGISTER", NULL, 800, 1, 0);
5071 nickserv_define_func("MERGEDB", cmd_mergedb, 999, 1, 0);
5072 nickserv_define_func("CHECKPASS", cmd_checkpass, 601, 1, 0);
5073 /* other options */
5074 dict_insert(nickserv_opt_dict, "INFO", opt_info);
5075 dict_insert(nickserv_opt_dict, "WIDTH", opt_width);
5076 dict_insert(nickserv_opt_dict, "TABLEWIDTH", opt_tablewidth);
5077 dict_insert(nickserv_opt_dict, "COLOR", opt_color);
5078 dict_insert(nickserv_opt_dict, "PRIVMSG", opt_privmsg);
5079 dict_insert(nickserv_opt_dict, "AUTOHIDE", opt_autohide);
5080 dict_insert(nickserv_opt_dict, "STYLE", opt_style);
5081 dict_insert(nickserv_opt_dict, "PASS", opt_password);
5082 dict_insert(nickserv_opt_dict, "PASSWORD", opt_password);
5083 dict_insert(nickserv_opt_dict, "FLAGS", opt_flags);
5084 dict_insert(nickserv_opt_dict, "ACCESS", opt_level);
5085 dict_insert(nickserv_opt_dict, "LEVEL", opt_level);
5086 dict_insert(nickserv_opt_dict, "EPITHET", opt_epithet);
5087 dict_insert(nickserv_opt_dict, "NOTE", opt_note);
5088 if (nickserv_conf.titlehost_suffix) {
5089 dict_insert(nickserv_opt_dict, "TITLE", opt_title);
5090 dict_insert(nickserv_opt_dict, "FAKEHOST", opt_fakehost);
5091 }
5092 dict_insert(nickserv_opt_dict, "ANNOUNCEMENTS", opt_announcements);
5093 dict_insert(nickserv_opt_dict, "MAXLOGINS", opt_maxlogins);
5094 dict_insert(nickserv_opt_dict, "ADVANCED", opt_advanced);
5095 dict_insert(nickserv_opt_dict, "LANGUAGE", opt_language);
5096
5097 nickserv_handle_dict = dict_new();
5098 dict_set_free_keys(nickserv_handle_dict, free);
5099 dict_set_free_data(nickserv_handle_dict, free_handle_info);
5100
5101 nickserv_id_dict = dict_new();
5102 dict_set_free_keys(nickserv_id_dict, free);
5103
5104 nickserv_nick_dict = dict_new();
5105 dict_set_free_data(nickserv_nick_dict, free);
5106
5107 nickserv_allow_auth_dict = dict_new();
5108
5109 userList_init(&curr_helpers);
5110
5111 if (nick) {
5112 const char *modes = conf_get_data("services/nickserv/modes", RECDB_QSTRING);
5113 nickserv = AddService(nick, modes ? modes : NULL, "Nick Services", NULL);
5114 nickserv_service = service_register(nickserv);
5115 }
5116 saxdb_register("NickServ", nickserv_saxdb_read, nickserv_saxdb_write);
5117 reg_exit_func(nickserv_db_cleanup);
5118 if(nickserv_conf.handle_expire_frequency)
5119 timeq_add(now + nickserv_conf.handle_expire_frequency, expire_handles, NULL);
5120
5121 if(autojoin_channels && nickserv) {
5122 for (i = 0; i < autojoin_channels->used; i++) {
5123 chan = AddChannel(autojoin_channels->list[i], now, "+nt", NULL, NULL);
5124 AddChannelUser(nickserv, chan)->modes |= MODE_CHANOP;
5125 }
5126 }
5127 #ifdef WITH_LDAP
5128 ldap_do_init(nickserv_conf);
5129 #endif
5130
5131 message_register_table(msgtab);
5132 }