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