#include "ircd.h"
#include "ircd_alloc.h"
#include "ircd_chattr.h"
+#include "ircd_events.h"
#include "ircd_features.h"
#include "ircd_log.h"
#include "ircd_osdep.h"
enum { AUTH_TIMEOUT = 60 };
+static void release_auth_client(struct Client* client);
+static void unlink_auth_request(struct AuthRequest* request,
+ struct AuthRequest** list);
+void free_auth_request(struct AuthRequest* auth);
+
+/*
+ * auth_timeout - timeout a given auth request
+ */
+static void auth_timeout_callback(struct Event* ev)
+{
+ struct AuthRequest* auth;
+
+ assert(0 != ev_timer(ev));
+ assert(0 != t_data(ev_timer(ev)));
+
+ auth = t_data(ev_timer(ev));
+
+ if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+ auth->flags &= ~AM_TIMEOUT;
+
+ if (!(auth->flags & AM_FREE_MASK)) {
+ Debug((DEBUG_LIST, "Freeing auth from timeout callback; %p [%p]", auth,
+ ev_timer(ev)));
+ MyFree(auth); /* done with it, finally */
+ }
+ } else {
+ assert(ev_type(ev) == ET_EXPIRE);
+
+ destroy_auth_request(auth, 1);
+ }
+}
+
+/*
+ * auth_sock_callback - called when an event occurs on the socket
+ */
+static void auth_sock_callback(struct Event* ev)
+{
+ struct AuthRequest* auth;
+
+ assert(0 != ev_socket(ev));
+ assert(0 != s_data(ev_socket(ev)));
+
+ auth = s_data(ev_socket(ev));
+
+ switch (ev_type(ev)) {
+ case ET_DESTROY: /* being destroyed */
+ auth->flags &= ~AM_SOCKET;
+
+ if (!(auth->flags & AM_FREE_MASK)) {
+ Debug((DEBUG_LIST, "Freeing auth from sock callback; %p [%p]", auth,
+ ev_socket(ev)));
+ MyFree(auth); /* done with it finally */
+ }
+ break;
+
+ case ET_CONNECT: /* socket connection completed */
+ Debug((DEBUG_LIST, "Connection completed for auth %p [%p]; sending query",
+ auth, ev_socket(ev)));
+ socket_state(&auth->socket, SS_CONNECTED);
+ send_auth_query(auth);
+ break;
+
+ case ET_READ: /* socket is readable */
+ case ET_EOF: /* end of file on socket */
+ case ET_ERROR: /* error on socket */
+ Debug((DEBUG_LIST, "Auth socket %p [%p] readable", auth, ev_socket(ev)));
+ read_auth_reply(auth);
+ break;
+
+ default:
+#ifndef NDEBUG
+ abort(); /* unrecognized event */
+#endif
+ break;
+ }
+}
+
+/*
+ * destroy_auth_request - stop an auth request completely
+ */
+void destroy_auth_request(struct AuthRequest* auth, int send_reports)
+{
+ struct AuthRequest** authList;
+
+ if (IsDoingAuth(auth)) {
+ authList = &AuthPollList;
+ if (-1 < auth->fd) {
+ close(auth->fd);
+ auth->fd = -1;
+ socket_del(&auth->socket);
+ }
+
+ if (send_reports && IsUserPort(auth->client))
+ sendheader(auth->client, REPORT_FAIL_ID);
+ } else
+ authList = &AuthIncompleteList;
+
+ if (IsDNSPending(auth)) {
+ delete_resolver_queries(auth);
+ if (send_reports && IsUserPort(auth->client))
+ sendheader(auth->client, REPORT_FAIL_DNS);
+ }
+
+ if (send_reports)
+ log_write(LS_RESOLVER, L_INFO, 0, "DNS/AUTH timeout %s",
+ get_client_name(auth->client, HIDE_IP));
+
+ release_auth_client(auth->client);
+ unlink_auth_request(auth, authList);
+ free_auth_request(auth);
+}
+
/*
* make_auth_request - allocate a new auth request
*/
(struct AuthRequest*) MyMalloc(sizeof(struct AuthRequest));
assert(0 != auth);
memset(auth, 0, sizeof(struct AuthRequest));
+ auth->flags = AM_TIMEOUT;
auth->fd = -1;
auth->client = client;
- auth->timeout = CurrentTime + AUTH_TIMEOUT;
+ cli_auth(client) = auth;
+ timer_add(&auth->timeout, auth_timeout_callback, (void*) auth, TT_RELATIVE,
+ AUTH_TIMEOUT);
return auth;
}
*/
void free_auth_request(struct AuthRequest* auth)
{
- if (-1 < auth->fd)
+ if (-1 < auth->fd) {
close(auth->fd);
- MyFree(auth);
+ Debug((DEBUG_LIST, "Deleting auth socket for %p", auth->client));
+ socket_del(&auth->socket);
+ }
+ Debug((DEBUG_LIST, "Deleting auth timeout timer for %p", auth->client));
+ timer_del(&auth->timeout);
}
/*
static void release_auth_client(struct Client* client)
{
assert(0 != client);
+ cli_auth(client) = 0;
cli_lasttime(client) = cli_since(client) = CurrentTime;
if (cli_fd(client) > HighestFd)
HighestFd = cli_fd(client);
LocalClientArray[cli_fd(client)] = client;
add_client_to_list(client);
+ socket_events(&(cli_socket(client)), SOCK_ACTION_SET | SOCK_EVENT_READABLE);
Debug((DEBUG_INFO, "Auth: release_auth_client %s@%s[%s]",
cli_username(client), cli_sockhost(client), cli_sock_ip(client)));
}
assert(0 != auth);
close(auth->fd);
auth->fd = -1;
+ socket_del(&auth->socket);
if (IsUserPort(auth->client))
sendheader(auth->client, REPORT_FAIL_ID);
struct sockaddr_in remote_addr;
struct sockaddr_in local_addr;
int fd;
+ IOResult result;
assert(0 != auth);
assert(0 != auth->client);
remote_addr.sin_port = htons(113);
remote_addr.sin_family = AF_INET;
- if (!os_connect_nonb(fd, &remote_addr)) {
+ if ((result = os_connect_nonb(fd, &remote_addr)) == IO_FAILURE ||
+ !socket_add(&auth->socket, auth_sock_callback, (void*) auth,
+ result == IO_SUCCESS ? SS_CONNECTED : SS_CONNECTING,
+ SOCK_EVENT_READABLE, fd)) {
ServerStats->is_abad++;
/*
* No error report from this...
return 0;
}
+ auth->flags |= AM_SOCKET;
auth->fd = fd;
SetAuthConnect(auth);
+ if (result == IO_SUCCESS)
+ send_auth_query(auth); /* this does a SetAuthPending(auth) for us */
+
return 1;
}
auth = make_auth_request(client);
assert(0 != auth);
+ Debug((DEBUG_INFO, "Beginning auth request on client %p", client));
+
if (!feature_bool(FEAT_NODNS)) {
if (LOOPBACK == inet_netof(cli_ip(client)))
strcpy(cli_sockhost(client), cli_name(&me));
HOSTLEN);
if (IsUserPort(auth->client))
sendheader(client, REPORT_FIN_DNSC);
+ Debug((DEBUG_LIST, "DNS entry for %p was cached", auth->client));
} else
SetDNSPending(auth);
}
}
- if (start_auth_query(auth))
+ if (start_auth_query(auth)) {
+ Debug((DEBUG_LIST, "identd query for %p initiated successfully",
+ auth->client));
link_auth_request(auth, &AuthPollList);
- else if (IsDNSPending(auth))
+ } else if (IsDNSPending(auth)) {
+ Debug((DEBUG_LIST, "identd query for %p not initiated successfully; "
+ "waiting on DNS", auth->client));
link_auth_request(auth, &AuthIncompleteList);
- else {
+ } else {
+ Debug((DEBUG_LIST, "identd query for %p not initiated successfully; "
+ "no DNS pending; releasing immediately", auth->client));
free_auth_request(auth);
release_auth_client(client);
}
}
-/*
- * timeout_auth_queries - timeout resolver and identd requests
- * allow clients through if requests failed
- */
-void timeout_auth_queries(time_t now)
-{
- struct AuthRequest* auth;
- struct AuthRequest* auth_next = 0;
-
- for (auth = AuthPollList; auth; auth = auth_next) {
- auth_next = auth->next;
- if (auth->timeout < CurrentTime) {
- if (-1 < auth->fd) {
- close(auth->fd);
- auth->fd = -1;
- }
-
- if (IsUserPort(auth->client))
- sendheader(auth->client, REPORT_FAIL_ID);
- if (IsDNSPending(auth)) {
- delete_resolver_queries(auth);
- if (IsUserPort(auth->client))
- sendheader(auth->client, REPORT_FAIL_DNS);
- }
- log_write(LS_RESOLVER, L_INFO, 0, "DNS/AUTH timeout %s",
- get_client_name(auth->client, HIDE_IP));
-
- release_auth_client(auth->client);
- unlink_auth_request(auth, &AuthPollList);
- free_auth_request(auth);
- }
- }
- for (auth = AuthIncompleteList; auth; auth = auth_next) {
- auth_next = auth->next;
- if (auth->timeout < CurrentTime) {
- delete_resolver_queries(auth);
- if (IsUserPort(auth->client))
- sendheader(auth->client, REPORT_FAIL_DNS);
- log_write(LS_RESOLVER, L_INFO, 0, "DNS timeout %s",
- get_client_name(auth->client, HIDE_IP));
-
- release_auth_client(auth->client);
- unlink_auth_request(auth, &AuthIncompleteList);
- free_auth_request(auth);
- }
- }
-}
-
/*
* send_auth_query - send the ident server a query giving "theirport , ourport"
* The write is only attempted *once* so it is deemed to be a fail if the
assert(0 != auth);
assert(0 != auth->client);
+ assert(auth = cli_auth(auth->client));
if (IO_SUCCESS == os_recv_nonb(auth->fd, buf, BUFSIZE, &len)) {
buf[len] = '\0';
+ Debug((DEBUG_LIST, "Auth %p [%p] reply: %s", auth, &auth->socket, buf));
username = check_ident_reply(buf);
+ Debug((DEBUG_LIST, "Username: %s", username));
}
close(auth->fd);
auth->fd = -1;
+ Debug((DEBUG_LIST, "Deleting auth [%p] socket %p", auth, &auth->socket));
+ socket_del(&auth->socket);
ClearAuth(auth);
if (!EmptyString(username)) {