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