if(cid_clients == NULL)
cid_clients = rb_dictionary_create("authd cid to uid mapping", rb_uint32cmp);
- if(bl_stats == NULL)
- bl_stats = rb_dictionary_create("blacklist statistics", rb_strcasecmp);
-
if(timeout_ev == NULL)
timeout_ev = rb_event_addish("timeout_dead_authd_clients", timeout_dead_authd_clients, NULL, 1);
sendto_realops_snomask(SNO_GENERAL, L_ALL, "Unable to start authd helper: %s", strerror(errno));
return 1;
}
+
ilog(L_MAIN, "authd helper started");
sendto_realops_snomask(SNO_GENERAL, L_ALL, "authd helper started");
rb_helper_run(authd_helper);
struct authd_cb *cmd;
parc = rb_string_to_array(buf, parv, MAXPARA+1);
- cmd = &authd_cmd_tab[*parv[0]];
+ cmd = &authd_cmd_tab[(unsigned char)*parv[0]];
if(cmd->fn != NULL)
{
if(cmd->min_parc > parc)
opm_check_enable(false);
}
+static void
+authd_free_client(struct Client *client_p)
+{
+ if(client_p == NULL || client_p->preClient == NULL)
+ return;
+
+ if(client_p->preClient->auth.cid == 0)
+ return;
+
+ if(authd_helper != NULL)
+ rb_helper_write(authd_helper, "E %x", client_p->preClient->auth.cid);
+
+ client_p->preClient->auth.accepted = true;
+ client_p->preClient->auth.cid = 0;
+}
+
+static void
+authd_free_client_cb(rb_dictionary_element *delem, void *unused)
+{
+ struct Client *client_p = delem->data;
+ authd_free_client(client_p);
+}
+
+void
+authd_abort_client(struct Client *client_p)
+{
+ rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(client_p->preClient->auth.cid));
+ authd_free_client(client_p);
+}
+
static void
restart_authd_cb(rb_helper * helper)
{
authd_helper = NULL;
}
- RB_DICTIONARY_FOREACH(client_p, &iter, cid_clients)
- {
- /* Abort any existing clients */
- authd_abort_client(client_p);
- }
+ rb_dictionary_destroy(cid_clients, authd_free_client_cb, NULL);
+ cid_clients = NULL;
start_authd();
configure_authd();
* gonna accept the client and ignore authd's suggestion.
*
* --Elizafox
+ *
+ * If this is an SSL connection we must defer handing off the client for
+ * reading until it is open and we have the certificate fingerprint, otherwise
+ * it's possible for the client to immediately send data before authd completes
+ * and before the status of the connection is communicated via ssld. This data
+ * could then be processed too early by read_packet().
*/
void
-authd_initiate_client(struct Client *client_p)
+authd_initiate_client(struct Client *client_p, bool defer)
{
char client_ipaddr[HOSTIPLEN+1];
char listen_ipaddr[HOSTIPLEN+1];
listen_port = ntohs(GET_SS_PORT(&client_p->preClient->lip));
client_port = ntohs(GET_SS_PORT(&client_p->localClient->ip));
+ if(defer)
+ client_p->preClient->auth.flags |= AUTHC_F_DEFERRED;
+
/* Add a bit of a fudge factor... */
client_p->preClient->auth.timeout = rb_current_time() + ConfigFileEntry.connect_timeout + 10;
rb_helper_write(authd_helper, "C %x %s %hu %s %hu", authd_cid, listen_ipaddr, listen_port, client_ipaddr, client_port);
}
+static inline void
+authd_read_client(struct Client *client_p)
+{
+ /*
+ * When a client has auth'ed, we want to start reading what it sends
+ * us. This is what read_packet() does.
+ * -- adrian
+ *
+ * Above comment was originally in s_auth.c, but moved here with below code.
+ * --Elizafox
+ */
+ rb_dlinkAddTail(client_p, &client_p->node, &global_client_list);
+ read_packet(client_p->localClient->F, client_p);
+}
+
/* When this is called we have a decision on client acceptance.
*
- * After this point authd no longer "owns" the client.
+ * After this point authd no longer "owns" the client, but if
+ * it's flagged as deferred then we're still waiting for a call
+ * to authd_deferred_client().
*/
static inline void
authd_decide_client(struct Client *client_p, const char *ident, const char *host, bool accept, char cause, const char *data, const char *reason)
if(*ident != '*')
{
rb_strlcpy(client_p->username, ident, sizeof(client_p->username));
+ SetGotId(client_p);
ServerStats.is_asuc++;
}
else
client_p->preClient->auth.reason = (reason == NULL ? NULL : rb_strdup(reason));
client_p->preClient->auth.cid = 0;
- /*
- * When a client has auth'ed, we want to start reading what it sends
- * us. This is what read_packet() does.
- * -- adrian
- *
- * Above comment was originally in s_auth.c, but moved here with below code.
- * --Elizafox
- */
- rb_dlinkAddTail(client_p, &client_p->node, &global_client_list);
- read_packet(client_p->localClient->F, client_p);
+ client_p->preClient->auth.flags |= AUTHC_F_COMPLETE;
+ if((client_p->preClient->auth.flags & AUTHC_F_DEFERRED) == 0)
+ authd_read_client(client_p);
+}
+
+void
+authd_deferred_client(struct Client *client_p)
+{
+ client_p->preClient->auth.flags &= ~AUTHC_F_DEFERRED;
+ if(client_p->preClient->auth.flags & AUTHC_F_COMPLETE)
+ authd_read_client(client_p);
}
/* Convenience function to accept client */
authd_decide_client(client_p, ident, host, false, cause, data, reason);
}
-void
-authd_abort_client(struct Client *client_p)
-{
- if(client_p == NULL || client_p->preClient == NULL)
- return;
-
- if(client_p->preClient->auth.cid == 0)
- return;
-
- rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(client_p->preClient->auth.cid));
-
- if(authd_helper != NULL)
- rb_helper_write(authd_helper, "E %x", client_p->preClient->auth.cid);
-
- client_p->preClient->auth.accepted = true;
- client_p->preClient->auth.cid = 0;
-}
-
static void
timeout_dead_authd_clients(void *notused __unused)
{
rb_dictionary_iter iter;
struct Client *client_p;
+ rb_dlink_list freelist = { NULL, NULL, 0 };
+ rb_dlink_node *ptr, *nptr;
RB_DICTIONARY_FOREACH(client_p, &iter, cid_clients)
{
if(client_p->preClient->auth.timeout < rb_current_time())
- authd_abort_client(client_p);
+ {
+ authd_free_client(client_p);
+ rb_dlinkAddAlloc(client_p, &freelist);
+ }
+ }
+
+ /* RB_DICTIONARY_FOREACH is not safe for deletion, so we do this crap */
+ RB_DLINK_FOREACH_SAFE(ptr, nptr, freelist.head)
+ {
+ client_p = ptr->data;
+ rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(client_p->preClient->auth.cid));
}
}
char filterbuf[BUFSIZE] = "*";
size_t s = 0;
+ if(bl_stats == NULL)
+ bl_stats = rb_dictionary_create("blacklist statistics", rb_strcasecmp);
+
/* Build a list of comma-separated values for authd.
* We don't check for validity - do it elsewhere.
*/
if(s)
filterbuf[s - 1] = '\0';
+ stats->host = rb_strdup(host);
stats->iptype = iptype;
stats->hits = 0;
rb_dictionary_add(bl_stats, host, stats);
struct BlacklistStats *stats = rb_dictionary_retrieve(bl_stats, host);
if(stats != NULL)
{
- rb_dictionary_delete(bl_stats, host);
+ rb_free(stats->host);
rb_free(stats);
+ rb_dictionary_delete(bl_stats, host);
}
rb_helper_write(authd_helper, "O rbl_del %s", host);
}
+static void
+blacklist_delete(rb_dictionary_element *delem, void *unused)
+{
+ struct BlacklistStats *stats = delem->data;
+
+ rb_free(stats->host);
+ rb_free(stats);
+}
+
/* Delete all the blacklists */
void
del_blacklist_all(void)
{
- struct BlacklistStats *stats;
- rb_dictionary_iter iter;
-
- RB_DICTIONARY_FOREACH(stats, &iter, bl_stats)
- {
- rb_free(stats);
- rb_dictionary_delete(bl_stats, iter.cur->key);
- }
+ if(bl_stats != NULL)
+ rb_dictionary_destroy(bl_stats, blacklist_delete, NULL);
+ bl_stats = NULL;
rb_helper_write(authd_helper, "O rbl_del_all");
}
}
conf_create_opm_listener(ip, port);
- rb_helper_write(authd_helper, "O opm_listener %s %hu", ip, port);
+ rb_helper_write(authd_helper, "O opm_listener %s %hu", ipbuf, port);
}
void