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