AR_IAUTH_HURRY, /**< we told iauth to hurry up */
AR_IAUTH_USERNAME, /**< iauth sent a username (preferred or forced) */
AR_IAUTH_FUSERNAME, /**< iauth sent a forced username */
+ AR_IAUTH_SOFT_DONE, /**< iauth has no objection to client */
AR_PASSWORD_CHECKED, /**< client password already checked */
AR_NUM_FLAGS
};
typedef int (*iauth_cmd_handler)(struct IAuth *iauth, struct Client *cli,
int parc, char **params);
+/** Copies a username, cleaning it in the process.
+ *
+ * @param[out] dest Destination buffer for user name.
+ * @param[in] src Source buffer for user name. Must be distinct from
+ * \a dest.
+ */
+void clean_username(char *dest, const char *src)
+{
+ int rlen = USERLEN;
+ char ch;
+
+ /* First character can be ~, later characters cannot. */
+ if (!IsCntrl(*src))
+ {
+ ch = *src++;
+ *dest++ = IsUserChar(ch) ? ch : '_';
+ rlen--;
+ }
+ while (rlen-- && !IsCntrl(ch = *src++))
+ {
+ *dest++ = (IsUserChar(ch) && (ch != '~')) ? ch : '_';
+ }
+ *dest = '\0';
+}
+
/** Set username for user associated with \a auth.
* @param[in] auth Client authorization request to work on.
* @return Zero if client is kept, CPTR_KILLED if client rejected.
struct User *user = cli_user(sptr);
char *d;
char *s;
- int rlen = USERLEN;
int killreason;
short upper = 0;
short lower = 0;
- short pos = 0;
short leadcaps = 0;
short other = 0;
short digits = 0;
char ch;
char last;
- if (FlagHas(&auth->flags, AR_IAUTH_USERNAME))
+ if (FlagHas(&auth->flags, AR_IAUTH_FUSERNAME))
{
- ircd_strncpy(cli_user(sptr)->username, cli_username(sptr), USERLEN);
+ ircd_strncpy(user->username, cli_username(sptr), USERLEN);
}
- else
+ else if (IsIdented(sptr))
{
- /* Copy username from source to destination. Since they may be the
- * same, and we may prefix with a '~', use a buffer character (ch)
- * to hold the next character to copy.
- */
- s = IsIdented(sptr) ? cli_username(sptr) : user->username;
- last = *s++;
- d = user->username;
- if (HasFlag(sptr, FLAG_DOID) && !IsIdented(sptr))
- {
- *d++ = '~';
- --rlen;
- }
- while (last && !IsCntrl(last) && rlen--)
+ clean_username(user->username, cli_username(sptr));
+ }
+ else if (HasFlag(sptr, FLAG_DOID))
+ {
+ /* Prepend ~ to user->username. */
+ s = user->username;
+ s[USERLEN] = '\0';
+ for (last = '~'; (ch = *s) != '\0'; )
{
- ch = *s++;
- *d++ = IsUserChar(last) ? last : '_';
- last = (ch != '~') ? ch : '_';
+ *s++ = last;
+ last = ch;
}
- *d = 0;
- }
+ *s++ = last;
+ *s = '\0';
+ } /* else cleaned version of client-provided name is in place */
/* If username is empty or just ~, reject. */
if ((user->username[0] == '\0')
s = d = user->username + (user->username[0] == '~');
for (last = '\0';
(ch = *d++) != '\0';
- pos++, last = ch)
+ last = ch)
{
if (IsLower(ch))
{
{
upper++;
/* Accept caps as leading if we haven't seen lower case or digits yet. */
- if ((leadcaps || pos == 0) && !lower && !digits)
+ if ((leadcaps || last == '\0') && !lower && !digits)
leadcaps++;
}
else if (IsDigit(ch))
{
digits++;
- if (pos == 0 || !IsDigit(last))
+ if (!IsDigit(last))
{
digitgroups++;
/* If more than two groups of digits, reject. */
{
other++;
/* If -_. exist at start, consecutively, or more than twice, reject. */
- if (pos == 0 || last == '-' || last == '_' || last == '.' || other > 2)
+ if (last == '\0' || last == '-' || last == '_' || last == '.' || other > 2)
goto badid;
}
else /* All other punctuation is rejected. */
/* Can this ever happen? */
case ACR_BAD_SOCKET:
++ServerStats->is_ref;
- IPcheck_connect_fail(cptr);
+ IPcheck_connect_fail(cptr, 0);
return exit_client(cptr, cptr, &me, "Unknown error -- Try again");
}
return 0;
if (IsUserPort(auth->client))
sendheader(auth->client, REPORT_FAIL_ID);
++ServerStats->is_abad;
+ if (IAuthHas(iauth, IAUTH_UNDERNET))
+ sendto_iauth(auth->client, "u");
} else {
if (IsUserPort(auth->client))
sendheader(auth->client, REPORT_FIN_ID);
/* Check for iauth timeout. */
if (FlagHas(&auth->flags, AR_IAUTH_PENDING)) {
- if (IAuthHas(iauth, IAUTH_REQUIRED)) {
+ if (IAuthHas(iauth, IAUTH_REQUIRED)
+ && !FlagHas(&auth->flags, AR_IAUTH_SOFT_DONE)) {
sendheader(cptr, REPORT_FAIL_IAUTH);
return exit_client_msg(cptr, cptr, &me, "Authorization Timeout");
}
}
auth->port = remote.port;
- /* Try to start DNS lookup. */
- start_dns_query(auth);
-
- /* Try to start ident lookup. */
- start_auth_query(auth);
-
/* Set required client inputs for users. */
if (IsUserPort(client)) {
cli_user(client) = make_user(client);
start_iauth_query(auth);
}
+ /* Try to start DNS lookup. */
+ start_dns_query(auth);
+
+ /* Try to start ident lookup. */
+ start_auth_query(auth);
+
/* Add client to GlobalClientList. */
add_client_to_list(client);
FlagClr(&auth->flags, AR_NEEDS_USER);
cptr = auth->client;
ircd_strncpy(cli_info(cptr), userinfo, REALLEN);
- ircd_strncpy(cli_user(cptr)->username, username, USERLEN);
+ clean_username(cli_user(cptr)->username, username);
ircd_strncpy(cli_user(cptr)->host, cli_sockhost(cptr), HOSTLEN);
if (IAuthHas(iauth, IAUTH_UNDERNET))
- sendto_iauth(cptr, "U %s %s %s :%s", username, hostname, servername, userinfo);
+ sendto_iauth(cptr, "U %s %s %s :%s", cli_user(cptr)->username, hostname, servername, userinfo);
else if (IAuthHas(iauth, IAUTH_ADDLINFO))
sendto_iauth(cptr, "U %s", username);
return check_auth_finished(auth);
if (iauth == NULL)
return;
- /* Close main socket. */
- if (s_fd(i_socket(iauth)) != -1) {
- close(s_fd(i_socket(iauth)));
- socket_del(i_socket(iauth));
- s_fd(i_socket(iauth)) = -1;
- }
-
/* Close error socket. */
if (s_fd(i_stderr(iauth)) != -1) {
close(s_fd(i_stderr(iauth)));
socket_del(i_stderr(iauth));
s_fd(i_stderr(iauth)) = -1;
}
+
+ /* Close main socket. */
+ if (s_fd(i_socket(iauth)) != -1) {
+ close(s_fd(i_socket(iauth)));
+ socket_del(i_socket(iauth));
+ s_fd(i_socket(iauth)) = -1;
+ }
}
/** Close all %IAuth connections marked as closing. */
memcpy(&auth->original, &cli_ip(cli), sizeof(auth->original));
/* Undo original IP connection in IPcheck. */
- IPcheck_connect_fail(cli);
+ IPcheck_connect_fail(cli, 1);
ClearIPChecked(cli);
/* Update the IP and charge them as a remote connect. */
return aconf;
}
+/** Tentatively accept a client in IAuth.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters.
+ * @param[in] params Optional class name for client.
+ * @return Negative (CPTR_KILLED) if the connection is refused, one otherwise.
+ */
+static int iauth_cmd_soft_done(struct IAuth *iauth, struct Client *cli,
+ int parc, char **params)
+{
+ /* Clear iauth pending flag. */
+ assert(cli_auth(cli) != NULL);
+ FlagSet(&cli_auth(cli)->flags, AR_IAUTH_SOFT_DONE);
+ return 1;
+}
+
/** Accept a client in IAuth.
* @param[in] iauth Active IAuth session.
* @param[in] cli Client referenced by command.
}
/* If account has a creation timestamp, use it. */
assert(cli_user(cli) != NULL);
- if (params[0][len] == ':')
+ if (params[0][len] == ':') {
cli_user(cli)->acc_create = strtoul(params[0] + len + 1, NULL, 10);
+ params[0][len] = '\0';
+ }
/* Copy account name to User structure. */
ircd_strncpy(cli_user(cli)->account, params[0], ACCOUNTLEN);
case 'I': handler = iauth_cmd_ip_address; has_cli = 1; break;
case 'M': handler = iauth_cmd_usermode; has_cli = 1; break;
case 'C': handler = iauth_cmd_challenge; has_cli = 1; break;
+ case 'd': handler = iauth_cmd_soft_done; has_cli = 1; break;
case 'D': handler = iauth_cmd_done_client; has_cli = 1; break;
case 'R': handler = iauth_cmd_done_account; has_cli = 1; break;
case 'k': /* The 'k' command indicates the user should be booted
switch (ev_type(ev)) {
case ET_DESTROY:
- /* Hm, what happened here? */
- if (!IAuthHas(iauth, IAUTH_CLOSING))
+ if (!IAuthHas(iauth, IAUTH_CLOSING) && !s_active(i_stderr(iauth)))
iauth_do_spawn(iauth, 1);
break;
case ET_READ:
switch (ev_type(ev)) {
case ET_DESTROY:
- /* We do not restart iauth here: the stdout handler does that for us. */
+ if (!IAuthHas(iauth, IAUTH_CLOSING) && !s_active(i_socket(iauth)))
+ iauth_do_spawn(iauth, 1);
break;
case ET_READ:
iauth_read_stderr(iauth);