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