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